Last active
August 30, 2025 03:43
-
-
Save sparr/e985a844b3df37d058de2748fc43ed14 to your computer and use it in GitHub Desktop.
C++ class containing multiple maps with the same key and value types, with a forward iterator across all of the maps
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <array> | |
#include <cassert> | |
#include <map> | |
#include <iterator> | |
template< typename Key, typename Value, int n > | |
class MapsContainer | |
{ | |
private: | |
std::array< std::map< Key, Value >, n > maps; | |
public: | |
class iterator | |
{ | |
private: | |
using MapIterator = typename std::map< Key, Value >::iterator; | |
MapIterator current; | |
// .begin() for each map except the first | |
std::array< MapIterator, n - 1 > begins; | |
// .end() for each map | |
std::array< MapIterator, n > ends; | |
size_t map_idx; | |
public: | |
// Iterator traits | |
using iterator_category = std::forward_iterator_tag; | |
using value_type = std::pair< const Key, Value >; | |
using difference_type = std::ptrdiff_t; | |
iterator( MapIterator current, | |
std::array< MapIterator, n - 1 > begins, | |
std::array< MapIterator, n > ends, | |
size_t map_idx = 0 ) | |
: current( current ), begins( begins ), ends( ends ), map_idx( map_idx ) { | |
assert( map_idx < ends.size() ); | |
// If we start at the end of map1, move to start of map2, | |
// repeat if necessary | |
while( current == ends[map_idx] && map_idx < begins.size() ) { | |
map_idx++; | |
current = begins[map_idx - 1]; | |
} | |
} | |
value_type &operator*() { | |
return *current; | |
} | |
value_type *operator->() { | |
return &( *current ); | |
} | |
iterator &operator++() { | |
current++; | |
while( current == ends[map_idx] && map_idx < begins.size() ) { | |
map_idx++; | |
current = begins[map_idx - 1]; | |
} | |
return *this; | |
} | |
iterator operator++( int ) { | |
iterator temp = *this; | |
++( *this ); | |
return temp; | |
} | |
bool operator==( const iterator &other ) const { | |
return map_idx == other.map_idx && current == other.current; | |
} | |
bool operator!=( const iterator &other ) const { | |
return !( *this == other ); | |
} | |
}; | |
class const_iterator | |
{ | |
private: | |
using MapConstIterator = typename std::map< Key, Value >::const_iterator; | |
MapConstIterator current; | |
// .begin() for each map except the first | |
std::array< MapConstIterator, n - 1 > begins; | |
// .end() for each map | |
std::array< MapConstIterator, n > ends; | |
size_t map_idx; | |
public: | |
using iterator_category = std::forward_iterator_tag; | |
using value_type = const std::pair<const Key, Value>; | |
using difference_type = std::ptrdiff_t; | |
const_iterator( MapConstIterator current, | |
std::array< MapConstIterator, n - 1 > begins, | |
std::array< MapConstIterator, n > ends, | |
size_t current_map = 0 ) | |
: current( current ), begins( begins ), ends( ends ), map_idx( current_map ) { | |
assert( current_map < ends.size() ); | |
// If we start at the end of map1, move to map2, repeat if necessary | |
while( current == ends[current_map] && current_map < begins.size() ) { | |
current_map++; | |
current = begins[current_map]; | |
} | |
} | |
value_type &operator*() const { | |
return *current; | |
} | |
value_type *operator->() const { | |
return &( *current ); | |
} | |
const_iterator &operator++() { | |
current++; | |
while( current == ends[map_idx] && map_idx < begins.size() ) { | |
map_idx++; | |
current = begins[map_idx]; | |
} | |
return *this; | |
} | |
const_iterator operator++( int ) { | |
const_iterator temp = *this; | |
++( *this ); | |
return temp; | |
} | |
bool operator==( const const_iterator &other ) const { | |
return map_idx == other.map_idx && current == other.current; | |
} | |
bool operator!=( const const_iterator &other ) const { | |
return !( *this == other ); | |
} | |
}; | |
// Standard container interface | |
iterator begin() { | |
std::array< typename std::map< Key, Value >::iterator, n - 1 > begins; | |
std::array< typename std::map< Key, Value >::iterator, n > ends; | |
size_t i = 0; | |
for( std::map< Key, Value > &map : maps ) { | |
if( i > 0 ) { | |
begins[i - 1] = maps[i].begin(); | |
} | |
ends[i] = maps[i].end(); | |
i++; | |
} | |
return iterator( maps[0].begin(), begins, ends, 0 ); | |
} | |
iterator end() { | |
std::array< typename std::map< Key, Value >::iterator, n - 1 > begins; | |
std::array< typename std::map< Key, Value >::iterator, n > ends; | |
size_t i = 0; | |
for( std::map< Key, Value > &map : maps ) { | |
if( i > 0 ) { | |
begins[i - 1] = maps[i].begin(); | |
} | |
ends[i] = maps[i].end(); | |
} | |
const size_t last_map_idx = maps.size() - 1; | |
return iterator( maps[last_map_idx].end(), begins, ends, last_map_idx ); | |
} | |
const_iterator begin() const { | |
std::array< typename std::map< Key, Value >::const_iterator, n - 1 > begins; | |
std::array< typename std::map< Key, Value >::const_iterator, n > ends; | |
size_t i = 0; | |
for( std::map< Key, Value > &map : maps ) { | |
if( i > 0 ) { | |
begins[i - 1] = maps[i].begin(); | |
} | |
ends[i] = maps[i].end(); | |
} | |
return const_iterator( maps[0].begin(), begins, ends, 0 ); | |
} | |
const_iterator end() const { | |
std::array< typename std::map< Key, Value >::const_iterator, n - 1 > begins; | |
std::array< typename std::map< Key, Value >::const_iterator, n > ends; | |
size_t i = 0; | |
for( std::map< Key, Value > &map : maps ) { | |
if( i > 0 ) { | |
begins[i - 1] = maps[i].begin(); | |
} | |
ends[i] = maps[i].end(); | |
} | |
const size_t last_map_idx = maps.size() - 1; | |
return const_iterator( maps[last_map_idx].end(), begins, ends, last_map_idx ); | |
} | |
const_iterator cbegin() const { | |
return begin(); | |
} | |
const_iterator cend() const { | |
return end(); | |
} | |
// Convenience methods to access individual maps | |
std::map< Key, Value > &getMap( size_t map_idx ) { | |
return maps[map_idx]; | |
} | |
const std::map< Key, Value > &getMap( size_t map_idx ) const { | |
return maps[map_idx]; | |
} | |
}; | |
// Usage example | |
#include <iostream> | |
#include <string> | |
int main() | |
{ | |
MapsContainer< std::string, std::string, 3 > container; | |
// Add some data to each map | |
container.getMap( 0 )["a"] = "0a"; | |
container.getMap( 1 )["b"] = "1b"; | |
container.getMap( 1 )["c"] = "1c"; | |
container.getMap( 2 )["d"] = "2d"; | |
container.getMap( 2 )["e"] = "2e"; | |
container.getMap( 2 )["f"] = "2f"; | |
// Iterate through all maps | |
std::cout << "All elements:\n"; | |
for( const auto &pair : container ) { | |
std::cout << "Key: " << pair.first << ", Value: " << pair.second << '\n'; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment