| 1 | #pragma once |
| 2 | |
| 3 | #include <Common/HashTable/FixedHashTable.h> |
| 4 | #include <Common/HashTable/HashMap.h> |
| 5 | |
| 6 | |
| 7 | template <typename Key, typename TMapped, typename TState = HashTableNoState> |
| 8 | struct FixedHashMapCell |
| 9 | { |
| 10 | using Mapped = TMapped; |
| 11 | using State = TState; |
| 12 | |
| 13 | using value_type = PairNoInit<Key, Mapped>; |
| 14 | using mapped_type = TMapped; |
| 15 | |
| 16 | bool full; |
| 17 | Mapped mapped; |
| 18 | |
| 19 | FixedHashMapCell() {} |
| 20 | FixedHashMapCell(const Key &, const State &) : full(true) {} |
| 21 | FixedHashMapCell(const value_type & value_, const State &) : full(true), mapped(value_.second) {} |
| 22 | |
| 23 | const VoidKey getKey() const { return {}; } |
| 24 | Mapped & getMapped() { return mapped; } |
| 25 | const Mapped & getMapped() const { return mapped; } |
| 26 | |
| 27 | bool isZero(const State &) const { return !full; } |
| 28 | void setZero() { full = false; } |
| 29 | |
| 30 | /// Similar to FixedHashSetCell except that we need to contain a pointer to the Mapped field. |
| 31 | /// Note that we have to assemble a continuous layout for the value_type on each call of getValue(). |
| 32 | struct CellExt |
| 33 | { |
| 34 | CellExt() {} |
| 35 | CellExt(Key && key_, const FixedHashMapCell * ptr_) : key(key_), ptr(const_cast<FixedHashMapCell *>(ptr_)) {} |
| 36 | void update(Key && key_, const FixedHashMapCell * ptr_) |
| 37 | { |
| 38 | key = key_; |
| 39 | ptr = const_cast<FixedHashMapCell *>(ptr_); |
| 40 | } |
| 41 | Key key; |
| 42 | FixedHashMapCell * ptr; |
| 43 | |
| 44 | const Key & getKey() const { return key; } |
| 45 | Mapped & getMapped() { return ptr->mapped; } |
| 46 | const Mapped & getMapped() const { return ptr->mapped; } |
| 47 | const value_type getValue() const { return {key, ptr->mapped}; } |
| 48 | }; |
| 49 | }; |
| 50 | |
| 51 | template <typename Key, typename Mapped, typename Cell = FixedHashMapCell<Key, Mapped>, typename Allocator = HashTableAllocator> |
| 52 | class FixedHashMap : public FixedHashTable<Key, Cell, Allocator> |
| 53 | { |
| 54 | public: |
| 55 | using Base = FixedHashTable<Key, Cell, Allocator>; |
| 56 | using Self = FixedHashMap; |
| 57 | using LookupResult = typename Base::LookupResult; |
| 58 | |
| 59 | using Base::Base; |
| 60 | |
| 61 | template <typename Func> |
| 62 | void ALWAYS_INLINE mergeToViaEmplace(Self & that, Func && func) |
| 63 | { |
| 64 | for (auto it = this->begin(), end = this->end(); it != end; ++it) |
| 65 | { |
| 66 | typename Self::LookupResult res_it; |
| 67 | bool inserted; |
| 68 | that.emplace(it->getKey(), res_it, inserted, it.getHash()); |
| 69 | func(res_it->getMapped(), it->getMapped(), inserted); |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | template <typename Func> |
| 74 | void ALWAYS_INLINE mergeToViaFind(Self & that, Func && func) |
| 75 | { |
| 76 | for (auto it = this->begin(), end = this->end(); it != end; ++it) |
| 77 | { |
| 78 | auto res_it = that.find(it->getKey(), it.getHash()); |
| 79 | if (!res_it) |
| 80 | func(it->getMapped(), it->getMapped(), false); |
| 81 | else |
| 82 | func(res_it->getMapped(), it->getMapped(), true); |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | template <typename Func> |
| 87 | void forEachValue(Func && func) |
| 88 | { |
| 89 | for (auto & v : *this) |
| 90 | func(v.getKey(), v.getMapped()); |
| 91 | } |
| 92 | |
| 93 | template <typename Func> |
| 94 | void forEachMapped(Func && func) |
| 95 | { |
| 96 | for (auto & v : *this) |
| 97 | func(v.getMapped()); |
| 98 | } |
| 99 | |
| 100 | Mapped & ALWAYS_INLINE operator[](const Key & x) |
| 101 | { |
| 102 | LookupResult it; |
| 103 | bool inserted; |
| 104 | this->emplace(x, it, inserted); |
| 105 | if (inserted) |
| 106 | new (&it->getMapped()) Mapped(); |
| 107 | |
| 108 | return it->getMapped(); |
| 109 | } |
| 110 | }; |
| 111 | |