| 240 | }; |
| 241 | |
| 242 | struct const_iterator { |
| 243 | // Standard iterator typedefs |
| 244 | // using difference_type = std::ptrdiff_t; |
| 245 | using value_type = pair<const Key, T>; |
| 246 | using pointer = const value_type *; |
| 247 | using reference = const value_type &; |
| 248 | using iterator_category = fl::forward_iterator_tag; |
| 249 | |
| 250 | const_iterator() FL_NOEXCEPT : _map(nullptr), _idx(0) {} |
| 251 | const_iterator(const unordered_map *m, fl::size idx) : _map(m), _idx(idx) { |
| 252 | advance_to_occupied(); |
| 253 | } |
| 254 | const_iterator(const iterator &it) : _map(it._map), _idx(it._idx) {} |
| 255 | |
| 256 | reference operator*() const { |
| 257 | auto &e = _map->_buckets[_idx]; |
| 258 | // Entry and pair<const Key, T> have the same memory layout |
| 259 | // Safe to reinterpret since we only add const to Key |
| 260 | return *fl::bit_cast<const value_type*>(&e); |
| 261 | } |
| 262 | |
| 263 | pointer operator->() const { |
| 264 | return &(operator*()); |
| 265 | } |
| 266 | |
| 267 | const_iterator &operator++() { |
| 268 | ++_idx; |
| 269 | advance_to_occupied(); |
| 270 | return *this; |
| 271 | } |
| 272 | |
| 273 | const_iterator operator++(int) { |
| 274 | const_iterator tmp = *this; |
| 275 | ++(*this); |
| 276 | return tmp; |
| 277 | } |
| 278 | |
| 279 | bool operator==(const const_iterator &o) const { |
| 280 | return _map == o._map && _idx == o._idx; |
| 281 | } |
| 282 | bool operator!=(const const_iterator &o) const { return !(*this == o); } |
| 283 | |
| 284 | void advance_to_occupied() { |
| 285 | if (!_map) |
| 286 | return; |
| 287 | fl::size cap = _map->_buckets.size(); |
| 288 | while (_idx < cap && !_map->is_occupied(_idx)) |
| 289 | ++_idx; |
| 290 | } |
| 291 | |
| 292 | friend class unordered_map; |
| 293 | |
| 294 | private: |
| 295 | const unordered_map *_map; |
| 296 | fl::size _idx; |
| 297 | }; |
| 298 | |
| 299 | iterator begin() { return iterator(this, 0); } |