1 /* 2 * Copyright (C) 2010-2011 Dmitry Marakasov 3 * 4 * This file is part of glosm. 5 * 6 * glosm is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * glosm is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with glosm. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #ifndef ID_MAP_HH 21 #define ID_MAP_HH 22 23 #include <vector> 24 25 /** 26 * Custom std::map-like container for storing OSM data effeciently. 27 * 28 * Uses lower bits of object id as a hash for no calculation overhead 29 * and pooled data storage to pack elements effeciently. 30 * 31 * Interface and usage semantics are the same as for std::map 32 */ 33 template <typename I, typename T, int BUCKET_COUNT_ORDER = 0, int REHASH_GROWTH_ORDER = 1, int ITEMS_PER_CHUNK = 16*65536> 34 class id_map { 35 static const size_t chunk_size = ITEMS_PER_CHUNK; 36 37 public: 38 typedef I key_type; 39 typedef T mapped_type; 40 typedef std::pair<const I, T> value_type; 41 42 typedef value_type* pointer; 43 typedef const value_type* const_pointer; 44 typedef value_type& reference; 45 typedef const value_type& const_reference; 46 47 private: 48 struct hash_node { 49 value_type data; 50 hash_node* next; 51 }; 52 53 typedef hash_node* hash_node_ptr; 54 typedef const hash_node* const_hash_node_ptr; 55 56 public: 57 struct iterator { 58 typedef iterator _self; 59 typedef id_map<I, T, BUCKET_COUNT_ORDER, REHASH_GROWTH_ORDER, ITEMS_PER_CHUNK> _map; 60 61 typedef const _map* const_map_ptr; 62 63 typedef typename _map::pointer pointer; 64 typedef typename _map::reference reference; 65 typedef typename _map::hash_node_ptr hash_node_ptr; 66 67 const_map_ptr map; 68 hash_node_ptr current; 69 iteratorid_map::iterator70 iterator() : map(), current() {} iteratorid_map::iterator71 iterator(const_map_ptr m) : map(m), current() {} iteratorid_map::iterator72 iterator(const_map_ptr m, hash_node_ptr c) : map(m), current(c) {} 73 operator ++id_map::iterator74 _self& operator++() { 75 if (current->next) 76 current = current->next; 77 else 78 current = map->findfirstafter(current->data.first); 79 return *this; 80 } 81 operator ++id_map::iterator82 _self operator++(int) { 83 _self tmp = *this; 84 if (current->next) 85 current = current->next; 86 else 87 current = map->findfirstafter(current->data.first); 88 return tmp; 89 } 90 operator *id_map::iterator91 reference operator*() const { 92 return current->data; 93 } 94 operator ->id_map::iterator95 pointer operator->() const { 96 return ¤t->data; 97 } 98 operator ==id_map::iterator99 bool operator==(const _self& x) const { 100 return x.current == current; 101 } 102 operator !=id_map::iterator103 bool operator!=(const _self& x) const { 104 return x.current != current; 105 } 106 }; 107 108 struct const_iterator { 109 typedef const_iterator _self; 110 typedef id_map<I, T, BUCKET_COUNT_ORDER, REHASH_GROWTH_ORDER, ITEMS_PER_CHUNK> _map; 111 112 typedef const _map* const_map_ptr; 113 114 typedef typename _map::iterator iterator; 115 116 typedef typename _map::const_pointer pointer; 117 typedef typename _map::const_reference reference; 118 typedef typename _map::const_hash_node_ptr const_hash_node_ptr; 119 120 const_map_ptr map; 121 const_hash_node_ptr current; 122 const_iteratorid_map::const_iterator123 const_iterator() : map(), current() {} const_iteratorid_map::const_iterator124 const_iterator(const_map_ptr m) : map(m) {} const_iteratorid_map::const_iterator125 const_iterator(const_map_ptr m, const_hash_node_ptr c) : map(m), current(c) {} const_iteratorid_map::const_iterator126 const_iterator(const iterator& it): map(it.map), current(it.current) {} 127 operator ++id_map::const_iterator128 _self& operator++() { 129 if (current->next) 130 current = current->next; 131 else 132 current = map->findfirstafter(current->data.first); 133 return *this; 134 } 135 operator ++id_map::const_iterator136 _self operator++(int) { 137 _self tmp = *this; 138 if (current->next) 139 current = current->next; 140 else 141 current = map->findfirstafter(current->data.first); 142 return tmp; 143 } 144 operator *id_map::const_iterator145 reference operator*() const { 146 return current->data; 147 } 148 operator ->id_map::const_iterator149 pointer operator->() const { 150 return ¤t->data; 151 } 152 operator ==id_map::const_iterator153 bool operator==(const _self& x) const { 154 return x.current == current; 155 } 156 operator !=id_map::const_iterator157 bool operator!=(const _self& x) const { 158 return x.current != current; 159 } 160 }; 161 162 public: 163 typedef std::vector<hash_node*> chunk_list; 164 165 public: id_map()166 id_map() { 167 init(); 168 } 169 ~id_map()170 virtual ~id_map() { 171 deinit(); 172 } 173 insert(const value_type & v)174 std::pair<iterator, bool> insert(const value_type& v) { 175 if (REHASH_GROWTH_ORDER > 0 && count > nbuckets * 2) 176 rehash(REHASH_GROWTH_ORDER); 177 178 hash_node* t = reinterpret_cast<hash_node*>(alloc()); 179 new((void*)&t->data)value_type(v); 180 181 /* No checking for existing element done - we assume OSM 182 * data to not have objects with duplicate id's */ 183 t->next = buckets[v.first & (nbuckets-1)]; 184 buckets[v.first & (nbuckets-1)] = t; 185 count++; 186 187 return std::make_pair(iterator(this, t), true); 188 } 189 size() const190 size_t size() const { 191 return count; 192 } 193 clear()194 void clear() { 195 deinit(); 196 init(); 197 } 198 find(key_type v)199 iterator find(key_type v) { 200 for (hash_node* n = buckets[v & (nbuckets-1)]; n; n = n->next) 201 if (n->data.first == v) 202 return iterator(this, n); 203 204 return end(); 205 } 206 find(key_type v) const207 const_iterator find(key_type v) const { 208 for (const hash_node* n = buckets[v & (nbuckets-1)]; n; n = n->next) 209 if (n->data.first == v) 210 return const_iterator(this, n); 211 212 return end(); 213 } 214 begin()215 iterator begin() { 216 if (count == 0) 217 return end(); 218 219 return iterator(this, findfirst()); 220 } 221 begin() const222 const_iterator begin() const { 223 if (count == 0) 224 return end(); 225 226 return const_iterator(this, findfirst()); 227 } 228 end()229 iterator end() { 230 return iterator(this, NULL); 231 } 232 end() const233 const_iterator end() const { 234 return const_iterator(this, NULL); 235 } 236 237 protected: findfirst() const238 hash_node* findfirst() const { 239 for (hash_node** b = buckets; b < buckets + nbuckets; ++b) 240 if (*b != NULL) 241 return *b; 242 243 return NULL; 244 } 245 findfirstfor(key_type v) const246 hash_node* findfirstfor(key_type v) const { 247 for (hash_node** b = buckets + (v & (nbuckets-1)); b < buckets + nbuckets; ++b) 248 if (*b != NULL) 249 return *b; 250 251 return NULL; 252 } 253 findfirstafter(key_type v) const254 hash_node* findfirstafter(key_type v) const { 255 for (hash_node** b = buckets + (v & (nbuckets-1)) + 1; b < buckets + nbuckets; ++b) 256 if (*b != NULL) 257 return *b; 258 259 return NULL; 260 } 261 alloc()262 hash_node* alloc() { 263 if (last_chunk_free == 0) { 264 /* chunk filled; allocate new one */ 265 chunks.push_back(reinterpret_cast<hash_node*>(::operator new(chunk_size*sizeof(hash_node)))); 266 current_ptr = chunks.back(); 267 last_chunk_free = chunk_size; 268 } 269 hash_node* ret = current_ptr; 270 current_ptr++; 271 last_chunk_free--; 272 return ret; 273 } 274 rehash(int k)275 void rehash(int k) { 276 int newnbuckets = nbuckets * (1 << k); 277 278 hash_node** newbuckets = new hash_node*[newnbuckets]; 279 memset(newbuckets, 0, newnbuckets * sizeof(hash_node*)); 280 281 for (hash_node** b = buckets; b < buckets + nbuckets; ++b) { 282 for (hash_node* n = *b; n != NULL; ) { 283 hash_node* cur = n; 284 n = n->next; 285 cur->next = newbuckets[cur->data.first & (newnbuckets-1)]; 286 newbuckets[cur->data.first & (newnbuckets-1)] = cur; 287 } 288 } 289 290 nbuckets = newnbuckets; 291 delete[] buckets; 292 buckets = newbuckets; 293 } 294 deinit()295 void deinit() { 296 for (typename chunk_list::iterator c = chunks.begin(); c != chunks.end(); ++c) { 297 /* Call destructors for assigned elements */ 298 for (hash_node* i = *c; i < ((*c == chunks.back()) ? (*c + chunk_size - last_chunk_free) : (*c + chunk_size)); ++i) { 299 i->data.~value_type(); 300 } 301 ::operator delete(*c); 302 } 303 304 chunks.clear(); 305 306 delete[] buckets; 307 } 308 init()309 void init() { 310 count = 0; 311 last_chunk_free = 0; 312 nbuckets = 1 << BUCKET_COUNT_ORDER; 313 buckets = new hash_node*[nbuckets]; 314 memset(buckets, 0, nbuckets * sizeof(hash_node*)); 315 } 316 317 protected: 318 /* hash table */ 319 size_t nbuckets; /* always power of 2, so nbuckets-1 is bitmask for hashing */ 320 hash_node** buckets; 321 size_t count; /* @todo superfluous - may be derived from nchunks and urrent_ptr */ 322 323 /* memory pool */ 324 chunk_list chunks; 325 size_t last_chunk_free; 326 hash_node* current_ptr; /* @todo superfluous - either last_chunk free or current_ptr should be removed */ 327 }; 328 329 #endif 330