Skip to content

Instantly share code, notes, and snippets.

@sparr
Last active August 30, 2025 03:43
Show Gist options
  • Save sparr/e985a844b3df37d058de2748fc43ed14 to your computer and use it in GitHub Desktop.
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
#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