1 /*
2  * Copyright (C) 2009-2012 Codership Oy <info@codership.com>
3  */
4 
5 /*!
6  * @file map.hpp
7  *
8  * This file contains templates that are thin wrappers for std::map
9  * and std::multimap with some extra functionality.
10  */
11 
12 #ifndef GCOMM_MAP_HPP
13 #define GCOMM_MAP_HPP
14 
15 #include "gu_serialize.hpp"
16 
17 #include <utility>
18 #include <iterator>
19 #include <map>
20 
21 #include "gcomm/exception.hpp"
22 #include "gcomm/types.hpp"
23 
24 namespace gcomm
25 {
26     template<typename K, typename V, typename C>
27     class MapBase
28     {
29         typedef C MapType;
30 
31     public:
32 
33         typedef typename MapType::iterator       iterator;
34         typedef typename MapType::const_iterator const_iterator;
35         typedef typename MapType::reverse_iterator reverse_iterator;
36         typedef typename MapType::const_reverse_iterator const_reverse_iterator;
37         typedef typename MapType::value_type     value_type;
38         typedef typename MapType::const_reference const_reference;
39         typedef typename MapType::key_type key_type;
40         typedef typename MapType::mapped_type mapped_type;
41 
42     protected:
43 
44         MapType map_;
45     public:
46 
MapBase()47         MapBase() : map_() {}
48 
~MapBase()49         virtual ~MapBase() {}
50 
begin()51         iterator begin()          { return map_.begin(); }
52 
end()53         iterator end()            { return map_.end();   }
54 
find(const K & k)55         iterator find(const K& k) { return map_.find(k); }
56 
find_checked(const K & k)57         iterator find_checked(const K& k)
58         {
59             iterator ret = map_.find(k);
60             if (ret == map_.end())
61             {
62                 gu_throw_fatal << "element " << k << " not found";
63             }
64             return ret;
65         }
66 
lower_bound(const K & k)67         iterator lower_bound(const K& k) { return map_.lower_bound(k); }
68 
begin() const69         const_iterator begin()          const { return map_.begin(); }
70 
end() const71         const_iterator end()            const { return map_.end();   }
72 
rbegin() const73         const_reverse_iterator rbegin()         const { return map_.rbegin(); }
74 
rend() const75         const_reverse_iterator rend()           const { return map_.rend(); }
76 
find(const K & k) const77         const_iterator find(const K& k) const { return map_.find(k); }
78 
find_checked(const K & k) const79         const_iterator find_checked(const K& k) const
80         {
81             const_iterator ret = map_.find(k);
82             if (ret == map_.end())
83             {
84                 gu_throw_fatal << "element " << k << " not found";
85             }
86             return ret;
87         }
88 
operator [](const key_type & k)89         mapped_type& operator[](const key_type& k) { return map_[k]; }
90 
erase(iterator i)91         void erase(iterator i) { map_.erase(i); }
92 
erase(iterator i,iterator j)93         void erase(iterator i, iterator j) { map_.erase(i, j); }
94 
erase(const K & k)95         void erase(const K& k) { map_.erase(k); }
96 
clear()97         void clear()           { map_.clear(); }
98 
size() const99         size_t size() const    { return map_.size(); }
100 
empty() const101         bool empty() const     { return map_.empty(); }
102 
serialize(gu::byte_t * const buf,size_t const buflen,size_t offset) const103         size_t serialize(gu::byte_t* const buf,
104                          size_t  const buflen,
105                          size_t        offset) const
106         {
107             gu_trace(offset = gu::serialize4(
108                          static_cast<uint32_t>(size()), buf, buflen, offset));
109             for (const_iterator i = map_.begin(); i != map_.end(); ++i)
110             {
111                 gu_trace(offset = key(i).serialize(buf, buflen, offset));
112                 gu_trace(offset = value(i).serialize(buf, buflen, offset));
113             }
114             return offset;
115         }
116 
unserialize(const gu::byte_t * buf,size_t const buflen,size_t offset)117         size_t unserialize(const gu::byte_t* buf,
118                            size_t const  buflen,
119                            size_t        offset)
120         {
121             uint32_t len;
122             // Clear map in case this object is reused
123             map_.clear();
124 
125             gu_trace(offset = gu::unserialize4(buf, buflen, offset, len));;
126 
127             for (uint32_t i = 0; i < len; ++i)
128             {
129                 K k;
130                 V v;
131                 gu_trace(offset = k.unserialize(buf, buflen, offset));
132                 gu_trace(offset = v.unserialize(buf, buflen, offset));
133                 if (map_.insert(std::make_pair(k, v)).second == false)
134                 {
135                     gu_throw_fatal << "Failed to unserialize map";
136                 }
137             }
138             return offset;
139         }
140 
serial_size() const141         size_t serial_size() const
142         {
143             return sizeof(uint32_t) + size()*(K::serial_size() + V::serial_size());
144         }
145 
operator ==(const MapBase & other) const146         bool operator==(const MapBase& other) const
147         {
148             return (map_ == other.map_);
149         }
150 
operator !=(const MapBase & other) const151         bool operator!=(const MapBase& other) const
152         {
153             return !(map_ == other.map_);
154         }
155 
key(const_iterator i)156         static const K& key(const_iterator i)
157         {
158             return i->first;
159         }
160 
key(iterator i)161         static const K& key(iterator i)
162         {
163             return i->first;
164         }
165 
value(const_iterator i)166         static const V& value(const_iterator i)
167         {
168             return i->second;
169         }
170 
value(iterator i)171         static V& value(iterator i)
172         {
173             return i->second;
174         }
175 
key(const value_type & vt)176         static const K& key(const value_type& vt)
177         {
178             return vt.first;
179         }
180 
value(value_type & vt)181         static V& value(value_type& vt)
182         {
183             return vt.second;
184         }
185 
value(const value_type & vt)186         static const V& value(const value_type& vt)
187         {
188             return vt.second;
189         }
190     };
191 
192     // @todo For some reason map key must be declared in gcomm namespace
193     //       in order this to work. Find out the reason why and fix.
194     template <typename K, typename V>
operator <<(std::ostream & os,const std::pair<K,V> & p)195     std::ostream& operator<<(std::ostream& os, const std::pair<K, V>& p)
196     {
197         return (os << "\t" << p.first << "," << p.second << "\n");
198     }
199 
200     template <typename K, typename V, typename C>
operator <<(std::ostream & os,const MapBase<K,V,C> & map)201     std::ostream& operator<<(std::ostream& os, const MapBase<K, V, C>& map)
202     {
203         std::copy(map.begin(), map.end(),
204                   std::ostream_iterator<const std::pair<const K, V> >(os, ""));
205         return os;
206     }
207 
208 
209     template <typename K, typename V, typename C = std::map<K, V> >
210     class Map : public MapBase<K, V, C>
211     {
212     public:
213         typedef typename MapBase<K, V, C>::iterator iterator;
insert(const std::pair<K,V> & p)214         std::pair<iterator, bool> insert(const std::pair<K, V>& p)
215         {
216             return MapBase<K, V, C>::map_.insert(p);
217         }
218 
insert(iterator pos,const std::pair<K,V> & p)219         iterator insert(iterator pos, const std::pair<K, V>& p)
220         {
221             return MapBase<K, V, C>::map_.insert(pos, p);
222         }
223 
224         template <class InputIterator>
insert(InputIterator first,InputIterator last)225         void insert(InputIterator first, InputIterator last)
226         {
227             MapBase<K, V, C>::map_.insert(first, last);
228         }
229 
insert_unique(const typename MapBase<K,V,C>::value_type & p)230         iterator insert_unique(const typename MapBase<K, V, C>::value_type& p)
231         {
232             std::pair<iterator, bool> ret = MapBase<K, V, C>::map_.insert(p);
233             if (false == ret.second)
234             {
235                 gu_throw_fatal << "duplicate entry "
236                                << "key=" << MapBase<K, V, C>::key(p) << " "
237                                << "value=" << MapBase<K, V, C>::value(p) << " "
238                                << "map=" << *this;
239             }
240             return ret.first;
241         }
242 
243     };
244 
245 
246 
247 
248     template <typename K, typename V, typename C = std::multimap<K, V> >
249     class MultiMap : public MapBase<K, V, C>
250     {
251     public:
252         typedef typename MapBase<K, V, C>::iterator iterator;
253         typedef typename MapBase<K, V, C>::const_iterator const_iterator;
254         typedef typename MapBase<K, V, C>::value_type value_type;
255         typedef typename MapBase<K, V, C>::const_reference const_reference;
256 
insert(const std::pair<K,V> & p)257         iterator insert(const std::pair<K, V>& p)
258         {
259             return MapBase<K, V, C>::map_.insert(p);
260         }
261 
insert(iterator position,const value_type & vt)262         iterator insert(iterator position, const value_type& vt)
263         {
264             return MapBase<K, V, C>::map_.insert(position, vt);
265         }
266 
equal_range(const K & k) const267         std::pair<const_iterator, const_iterator> equal_range(const K& k) const
268         {
269             return MapBase<K, V, C>::map_.equal_range(k);
270         }
271     };
272 }
273 #endif /* GCOMM_MAP_HPP */
274