|
16 | 16 | namespace bsp {
|
17 | 17 |
|
18 | 18 | namespace fixed_map_detail {
|
19 |
| -template<class, class Enable = void> struct is_iterator : std::false_type {}; |
20 |
| -template<typename T_> |
| 19 | +template <class, class Enable = void> struct is_iterator : std::false_type {}; |
| 20 | +template <typename T_> |
21 | 21 | struct is_iterator<
|
22 |
| - T_, typename std::enable_if< |
23 |
| - std::is_base_of<std::input_iterator_tag, |
24 |
| - typename std::iterator_traits<T_>::iterator_category>::value || |
25 |
| - std::is_same<std::output_iterator_tag, |
26 |
| - typename std::iterator_traits<T_>::iterator_category>::value>::type> |
27 |
| - : std::true_type {}; |
| 22 | + T_, typename std::enable_if< |
| 23 | + std::is_base_of< |
| 24 | + std::input_iterator_tag, |
| 25 | + typename std::iterator_traits<T_>::iterator_category>::value || |
| 26 | + std::is_same<std::output_iterator_tag, |
| 27 | + typename std::iterator_traits<T_>::iterator_category>:: |
| 28 | + value>::type> : std::true_type {}; |
28 | 29 | } // namespace fixed_map_detail
|
29 | 30 |
|
30 | 31 | // A simple map of elements stored in a fixed-size array.
|
31 | 32 | // Is essentially a hashmap with open addressing and linear probing.
|
32 |
| -template<typename Key, typename T, int Capacity, class Hash = std::hash<Key>> |
| 33 | +template <typename Key, typename T, int Capacity, class Hash = std::hash<Key>> |
33 | 34 | class fixed_map {
|
34 |
| - static_assert(Capacity > 0, "Capacity <= 0!"); |
| 35 | + static_assert(Capacity > 0, "Capacity <= 0!"); |
35 | 36 |
|
36 | 37 | public:
|
37 |
| - struct slot { |
38 |
| - Key key; |
39 |
| - T value; |
40 |
| - bool valid = false; |
41 |
| - }; |
42 |
| - |
43 |
| - using array_type = std::array<slot, Capacity>; |
44 |
| - |
45 |
| - using key_type = Key; |
46 |
| - using mapped_type = T; |
47 |
| - using value_type = slot; |
48 |
| - using reference = T&; |
49 |
| - using const_reference = const T&; |
50 |
| - using iterator = typename array_type::iterator; |
51 |
| - using const_iterator = typename array_type::const_iterator; |
52 |
| - using size_type = int; |
| 38 | + struct slot { |
| 39 | + Key key; |
| 40 | + T value; |
| 41 | + bool valid = false; |
| 42 | + }; |
| 43 | + |
| 44 | + using array_type = std::array<slot, Capacity>; |
| 45 | + |
| 46 | + using key_type = Key; |
| 47 | + using mapped_type = T; |
| 48 | + using value_type = slot; |
| 49 | + using reference = T &; |
| 50 | + using const_reference = const T &; |
| 51 | + using iterator = typename array_type::iterator; |
| 52 | + using const_iterator = typename array_type::const_iterator; |
| 53 | + using size_type = int; |
53 | 54 |
|
54 | 55 | public:
|
55 |
| - fixed_map(const T& invalid_value = T()) : size_(0), invalid_value_(invalid_value) { clear(); } |
| 56 | + fixed_map(const T &invalid_value = T()) |
| 57 | + : size_(0), invalid_value_(invalid_value) { |
| 58 | + clear(); |
| 59 | + } |
56 | 60 |
|
57 |
| - template<class Container> fixed_map(const Container& els) : fixed_map(els.begin(), els.end()) {} |
| 61 | + template <class Container> |
| 62 | + fixed_map(const Container &els) : fixed_map(els.begin(), els.end()) {} |
58 | 63 |
|
59 |
| - fixed_map(std::initializer_list<std::pair<Key, T>> list) |
60 |
| - : fixed_map(list.begin(), list.end()) {} |
| 64 | + fixed_map(std::initializer_list<std::pair<Key, T>> list) |
| 65 | + : fixed_map(list.begin(), list.end()) {} |
61 | 66 |
|
62 |
| - inline void clear() { |
63 |
| - size_ = 0; |
64 |
| - std::fill(data_.begin(), data_.end(), value_type()); |
65 |
| - } |
| 67 | + inline void clear() { |
| 68 | + size_ = 0; |
| 69 | + std::fill(data_.begin(), data_.end(), value_type()); |
| 70 | + } |
66 | 71 |
|
67 |
| - inline bool empty() const { return size_ == 0; } |
| 72 | + inline bool empty() const { return size_ == 0; } |
68 | 73 |
|
69 |
| - inline size_type size() const { return size_; } |
| 74 | + inline size_type size() const { return size_; } |
70 | 75 |
|
71 |
| - static constexpr inline size_type max_size() { return Capacity; } |
| 76 | + static constexpr inline size_type max_size() { return Capacity; } |
72 | 77 |
|
73 |
| - bool has(const key_type& key) const { |
74 |
| - return find_index(key) != -1; |
75 |
| - } |
| 78 | + bool has(const key_type &key) const { return find_index(key) != -1; } |
76 | 79 |
|
77 |
| - inline const_reference find(const key_type& key) const { |
78 |
| - auto index = find_index(key); |
79 |
| - if (index != -1) return data_[index].value; |
80 |
| - else return invalid_value_; |
81 |
| - } |
| 80 | + inline const_reference find(const key_type &key) const { |
| 81 | + auto index = find_index(key); |
| 82 | + if (index != -1) |
| 83 | + return data_[index].value; |
| 84 | + else |
| 85 | + return invalid_value_; |
| 86 | + } |
82 | 87 |
|
83 |
| - inline reference find(const key_type& key) { |
84 |
| - auto index = find_index(key); |
85 |
| - if (index != -1) return data_[index].value; |
86 |
| - else return invalid_value_; |
87 |
| - } |
| 88 | + inline reference find(const key_type &key) { |
| 89 | + auto index = find_index(key); |
| 90 | + if (index != -1) |
| 91 | + return data_[index].value; |
| 92 | + else |
| 93 | + return invalid_value_; |
| 94 | + } |
88 | 95 |
|
89 |
| - reference operator[](const key_type& key) { return find(key); } |
| 96 | + reference operator[](const key_type &key) { return find(key); } |
90 | 97 |
|
91 |
| - const_reference operator[](const key_type& key) const { return find(key); } |
| 98 | + const_reference operator[](const key_type &key) const { return find(key); } |
92 | 99 |
|
93 |
| - template<typename Key_> iterator insert(const Key_& key, const T& value) { |
94 |
| - if (size_ >= max_size()) { |
| 100 | + template <typename Key_> iterator insert(const Key_ &key, const T &value) { |
| 101 | + if (size_ >= max_size()) { |
95 | 102 | #ifdef BSP_FIXED_MAP_THROWS
|
96 |
| - throw std::length_error("fixed_map: trying to insert too many elements"); |
| 103 | + throw std::length_error("fixed_map: trying to insert too many elements"); |
97 | 104 | #endif
|
98 |
| - } |
99 |
| - size_type index = hash_to_index(key); |
100 |
| - size_type oindex = index; |
101 |
| - while (data_[index].valid) { |
102 |
| - index = (index + 1) % max_size(); |
103 |
| - if (index == oindex) { |
104 |
| - // TODO: This should be unreachable? |
105 |
| - assert(false); |
106 |
| - return begin(); |
107 |
| - } |
108 |
| - } |
109 |
| - data_[index].key = key; |
110 |
| - data_[index].value = value; |
111 |
| - data_[index].valid = true; |
112 |
| - size_++; |
113 |
| - return std::next(data_.begin(), index); |
114 |
| - } |
115 |
| - |
116 |
| - iterator begin() { return data_.begin(); } |
117 |
| - iterator end() { return begin() + max_size(); } |
118 |
| - |
119 |
| - const_iterator begin() const { return data_.begin(); } |
120 |
| - const_iterator end() const { return begin() + max_size(); } |
| 105 | + } |
| 106 | + size_type index = hash_to_index(key); |
| 107 | + size_type oindex = index; |
| 108 | + while (data_[index].valid) { |
| 109 | + index = (index + 1) % max_size(); |
| 110 | + if (index == oindex) { |
| 111 | + // TODO: This should be unreachable? |
| 112 | + assert(false); |
| 113 | + return begin(); |
| 114 | + } |
| 115 | + } |
| 116 | + data_[index].key = key; |
| 117 | + data_[index].value = value; |
| 118 | + data_[index].valid = true; |
| 119 | + size_++; |
| 120 | + return std::next(data_.begin(), index); |
| 121 | + } |
| 122 | + |
| 123 | + iterator begin() { return data_.begin(); } |
| 124 | + iterator end() { return begin() + max_size(); } |
| 125 | + |
| 126 | + const_iterator begin() const { return data_.begin(); } |
| 127 | + const_iterator end() const { return begin() + max_size(); } |
121 | 128 |
|
122 | 129 | protected:
|
123 |
| - size_type size_ = 0; |
124 |
| - array_type data_; |
125 |
| - T invalid_value_; |
| 130 | + size_type size_ = 0; |
| 131 | + array_type data_; |
| 132 | + T invalid_value_; |
126 | 133 |
|
127 | 134 | protected:
|
128 |
| - template<typename Iter, |
129 |
| - typename = typename std::enable_if< |
130 |
| - fixed_map_detail::is_iterator<Iter>::value>::type> |
131 |
| - fixed_map(Iter begin_, Iter end_) { |
| 135 | + template <typename Iter, |
| 136 | + typename = typename std::enable_if< |
| 137 | + fixed_map_detail::is_iterator<Iter>::value>::type> |
| 138 | + fixed_map(Iter begin_, Iter end_) { |
132 | 139 | #ifdef BSP_FIXED_MAP_THROWS
|
133 |
| - auto size = static_cast<size_type>(std::distance(begin_, end_)); |
134 |
| - if (size > max_size()) throw std::length_error("fixed_map: too many elements"); |
| 140 | + auto size = static_cast<size_type>(std::distance(begin_, end_)); |
| 141 | + if (size > max_size()) |
| 142 | + throw std::length_error("fixed_map: too many elements"); |
135 | 143 | #endif
|
136 |
| - for (auto it = begin_; it != end_; ++it) { |
137 |
| - insert(it->first, it->second); |
138 |
| - } |
139 |
| - } |
140 |
| - |
141 |
| - static inline std::size_t hash(const key_type& key) { return Hash{}(key); } |
142 |
| - |
143 |
| - static inline size_type hash_to_index(const key_type& key) { return static_cast<size_type>(hash(key) % max_size()); } |
144 |
| - |
145 |
| - inline size_type find_index(const key_type& key) const { |
146 |
| - auto start_index = hash_to_index(key); |
147 |
| - auto index = start_index; |
148 |
| - do { |
149 |
| - const auto& slot = data_[index]; |
150 |
| - if (slot.valid && slot.key == key) { |
151 |
| - return index; |
152 |
| - } |
153 |
| - index = (index + 1) % max_size(); |
154 |
| - } |
155 |
| - while (index != start_index); |
156 |
| - return -1; |
157 |
| - } |
158 |
| - |
159 |
| - template<typename Key_, typename T_, int Capacity_, class Hash_> |
160 |
| - friend std::ostream& operator<<(std::ostream&, const fixed_map<Key_, T_, Capacity_, Hash_>&); |
| 144 | + for (auto it = begin_; it != end_; ++it) { |
| 145 | + insert(it->first, it->second); |
| 146 | + } |
| 147 | + } |
| 148 | + |
| 149 | + static inline std::size_t hash(const key_type &key) { return Hash{}(key); } |
| 150 | + |
| 151 | + static inline size_type hash_to_index(const key_type &key) { |
| 152 | + return static_cast<size_type>(hash(key) % max_size()); |
| 153 | + } |
| 154 | + |
| 155 | + inline size_type find_index(const key_type &key) const { |
| 156 | + auto start_index = hash_to_index(key); |
| 157 | + auto index = start_index; |
| 158 | + do { |
| 159 | + const auto &slot = data_[index]; |
| 160 | + if (slot.valid && slot.key == key) { |
| 161 | + return index; |
| 162 | + } |
| 163 | + index = (index + 1) % max_size(); |
| 164 | + } while (index != start_index); |
| 165 | + return -1; |
| 166 | + } |
| 167 | + |
| 168 | + template <typename Key_, typename T_, int Capacity_, class Hash_> |
| 169 | + friend std::ostream & |
| 170 | + operator<<(std::ostream &, const fixed_map<Key_, T_, Capacity_, Hash_> &); |
161 | 171 | };
|
162 | 172 |
|
163 |
| -template<typename Key_, typename T_, int Capacity_, class Hash_> |
164 |
| -inline std::ostream& operator<<(std::ostream& out, |
165 |
| - const fixed_map<Key_, T_, Capacity_, Hash_>& map) { |
166 |
| - out << "fixed_map<" << Capacity_ << "> {"; |
167 |
| - if (map.empty()) |
168 |
| - out << "}"; |
169 |
| - else { |
170 |
| - for (auto it = map.data_.begin(); it != map.data_.end(); ++it) { |
171 |
| - const auto& el = *it; |
172 |
| - if (el.valid) |
173 |
| - out << el.key << ": " << el.value; |
174 |
| - else |
175 |
| - out << "_"; |
176 |
| - if (std::next(it) != map.data_.end()) |
177 |
| - out << ", "; |
178 |
| - } |
179 |
| - out << "}"; |
180 |
| - } |
181 |
| - return out; |
| 173 | +template <typename Key_, typename T_, int Capacity_, class Hash_> |
| 174 | +inline std::ostream & |
| 175 | +operator<<(std::ostream &out, |
| 176 | + const fixed_map<Key_, T_, Capacity_, Hash_> &map) { |
| 177 | + out << "fixed_map<" << Capacity_ << "> {"; |
| 178 | + if (map.empty()) |
| 179 | + out << "}"; |
| 180 | + else { |
| 181 | + for (auto it = map.data_.begin(); it != map.data_.end(); ++it) { |
| 182 | + const auto &el = *it; |
| 183 | + if (el.valid) |
| 184 | + out << el.key << ": " << el.value; |
| 185 | + else |
| 186 | + out << "_"; |
| 187 | + if (std::next(it) != map.data_.end()) |
| 188 | + out << ", "; |
| 189 | + } |
| 190 | + out << "}"; |
| 191 | + } |
| 192 | + return out; |
182 | 193 | }
|
183 | 194 |
|
184 | 195 | } // namespace bsp
|
|
0 commit comments