Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::map of iterators to itself

My goal is to map elements of a type to other elements of the same type. Suppose they are size_t for simplicity.

std::map<size_t, size_t> myMapping;

This would do it, but if I want to follow a bunch of such links (they are all the same map), each step is a log(n) lookup.

size_t k = /*whatever*/;
myMapping[myMapping[myMapping[k]]];   //3 * log(n)

I want to make use of the fact that map iterators remain valid and have a map that maps size_t to iterators into itself.

typedef /*myMapTemplate*/::iterator map_iter;
std::map<size_t, map_iter> myMapping;

size_t k = /*whatever*/
map_iter entryPoint = myMapping.find(k);
entryPoint->second->second->first;   //log(n) + 2 constant time operations

How would I write this type? I know copying would keep iterators to old map and plan to take care of this myself.

like image 270
Filipp Avatar asked Oct 10 '12 10:10

Filipp


2 Answers

I understand your question that you want map: key->map<key,>::iterator

So, here it is, a struct with map iterator as value:

template <
    template <class K, class V, class C, class A> class mapImpl, 
   class K, 
   class V, 
   class C=std::less<K>, 
   class A=std::allocator<std::pair<const K, V> >
>
class value_with_iterator {
public:
   typedef typename mapImpl<const K,value_with_iterator,C,A>::iterator value_type;
   value_type value;
};

Map defined with using struct above:

typedef std::map<size_t, value_with_iterator <std::map, size_t, size_t> > map_size_t_to_itself;

Some insert method - to link key with itself:

map_size_t_to_itself::iterator insert(map_size_t_to_itself& mapRef, size_t value)
{
   map_size_t_to_itself::value_type v(value, map_size_t_to_itself::mapped_type());
   std::pair<map_size_t_to_itself::iterator, bool> res = mapRef.insert(v);
   if (res.second) 
     res.first->second.value = res.first;
   return res.first;
}

And simple test:

int main() {
   map_size_t_to_itself mapObj;
   map_size_t_to_itself::iterator i1 = insert(mapObj, 1);
   map_size_t_to_itself::iterator i2 = insert(mapObj, 1);
   map_size_t_to_itself::iterator i3 = insert(mapObj, 2);

   std::cout << i1->first << ": " << i1->second.value->first << std::endl;
   std::cout << i2->first << ": " << i2->second.value->first << std::endl;
   std::cout << i3->first << ": " << i3->second.value->first << std::endl;
}

with OUTPUT:

1: 1
1: 1
2: 2

Full link: http://ideone.com/gnEhw

like image 184
PiotrNycz Avatar answered Oct 15 '22 15:10

PiotrNycz


If I understood your problem correctly, I think I would keep my elements in a vector and use a vector of indices into the first vector for the kind of indirection you want. If you also need ordered access you can always throw in a map to the elements of the first vector.

like image 42
Nicola Musatti Avatar answered Oct 15 '22 14:10

Nicola Musatti