Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
flat_map_test.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 https://github.com/lrleon/Aleph-w
6
7 This file is part of Aleph-w library
8
9 Copyright (c) 2002-2026 Leandro Rabindranath Leon
10
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be included in all
19 copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 SOFTWARE.
28*/
29
40#include <iterator>
41#include <map>
42#include <random>
43#include <stdexcept>
44#include <string>
45#include <utility>
46#include <vector>
47
48#include <gtest/gtest.h>
49
50#include <tpl_flat_map.H>
51
52using Aleph::FlatMap;
53
54namespace
55{
56class Pair_Input_Iterator
57{
58 const std::vector<std::pair<int, std::string>> *items_ = nullptr;
59 size_t pos_ = 0;
60
61public:
62
63 using iterator_category = std::input_iterator_tag;
64 using value_type = std::pair<int, std::string>;
65 using difference_type = std::ptrdiff_t;
66 using pointer = void;
67 using reference = const value_type &;
68
69 Pair_Input_Iterator() = default;
70
71 Pair_Input_Iterator(const std::vector<std::pair<int, std::string>> &items,
72 size_t pos) noexcept
73 : items_(&items), pos_(pos) {}
74
75 reference operator*() const noexcept { return (*items_)[pos_]; }
76
77 Pair_Input_Iterator &operator++() noexcept
78 {
79 ++pos_;
80 return *this;
81 }
82
83 Pair_Input_Iterator operator++(int) noexcept
84 {
85 Pair_Input_Iterator ret = *this;
86 ++(*this);
87 return ret;
88 }
89
90 bool operator==(const Pair_Input_Iterator &it) const noexcept
91 {
92 return items_ == it.items_ and pos_ == it.pos_;
93 }
94
95 bool operator!=(const Pair_Input_Iterator &it) const noexcept
96 {
97 return not (*this == it);
98 }
99};
100} // namespace
101
111
113{
115 m["b"] = 2;
116 m["a"] = 1;
117 m["c"] = 3;
118 ASSERT_EQ(m.size(), 3u);
119
120 m["a"] += 10; // update through subscript
121 EXPECT_EQ(m.at("a"), 11);
122
123 // Absent key gets a default-constructed value.
124 EXPECT_EQ(m["zz"], 0);
125 EXPECT_EQ(m.size(), 4u);
126
127 // Keys must come out sorted.
128 EXPECT_EQ(m.nth_key(0), "a");
129 EXPECT_EQ(m.nth_key(1), "b");
130 EXPECT_EQ(m.nth_key(2), "c");
131 EXPECT_EQ(m.nth_key(3), "zz");
132}
133
135{
136 FlatMap<std::string, int> m = {{"a", 1}};
137 EXPECT_EQ(m.at("a"), 1);
138 EXPECT_THROW((void) m.at("nope"), std::out_of_range);
139
141 EXPECT_EQ(cm.at("a"), 1);
142 EXPECT_THROW((void) cm.at("nope"), std::out_of_range);
143}
144
146{
147 FlatMap<int, std::string> m = {{3, "three"}, {1, "one"},
148 {3, "THREE"}, {2, "two"}};
149 ASSERT_EQ(m.size(), 3u);
150 EXPECT_EQ(m.at(3), "three"); // first occurrence wins
151 EXPECT_EQ(m.nth_key(0), 1);
152 EXPECT_EQ(m.nth_key(2), 3);
153}
154
156{
157 const std::vector<std::pair<int, std::string>> items =
158 {{3, "three"}, {1, "one"}, {2, "two"}};
159
160 FlatMap<int, std::string> m(Pair_Input_Iterator(items, 0),
161 Pair_Input_Iterator(items, items.size()));
162
163 ASSERT_EQ(m.size(), 3u);
164 EXPECT_EQ(m.at(1), "one");
165 EXPECT_EQ(m.at(2), "two");
166 EXPECT_EQ(m.at(3), "three");
167}
168
169// The map's own iterators yield a (key, value) proxy with no common
170// reference with std::pair, so they do not model std::input_iterator; the
171// range constructor must still accept them.
173{
174 FlatMap<int, std::string> src = {{2, "two"}, {1, "one"}, {3, "three"}};
175 const FlatMap<int, std::string> &csrc = src;
176
180
181 EXPECT_EQ(from_it, src);
182 EXPECT_EQ(from_cit, src);
183 ASSERT_EQ(from_tail.size(), 2u);
184 EXPECT_FALSE(from_tail.contains(1));
185 EXPECT_EQ(from_tail.at(3), "three");
186}
187
189{
191 EXPECT_TRUE(m.insert(1, 100).second);
192 EXPECT_FALSE(m.insert(1, 999).second);
193 EXPECT_EQ(m.at(1), 100); // original value kept
194
195 EXPECT_FALSE(m.insert_or_assign(1, 999).second);
196 EXPECT_EQ(m.at(1), 999); // overwritten
197
198 EXPECT_TRUE(m.insert_or_assign(2, 200).second);
199 EXPECT_EQ(m.at(2), 200);
200
201 // Pair-based insert.
202 EXPECT_TRUE(m.insert(std::pair<int, int>(3, 300)).second);
203 EXPECT_EQ(m.at(3), 300);
204}
205
207{
208 FlatMap<int, int> m = {{1, 10}, {2, 20}, {3, 30}, {4, 40}};
209
210 EXPECT_EQ(m.erase(2), 1u);
211 EXPECT_EQ(m.erase(2), 0u);
212 EXPECT_EQ(m.size(), 3u);
213
214 auto it = m.find(3);
215 ASSERT_NE(it, m.end());
216 it = m.erase(it);
217 EXPECT_EQ((*it).first, 4); // entry following the erased one
218 EXPECT_EQ(m.size(), 2u);
219
220 EXPECT_THROW((void) m.erase(m.end()), std::out_of_range);
221}
222
224{
225 FlatMap<std::string, int> m = {{"b", 2}, {"a", 1}, {"c", 3}};
226
227 std::vector<std::string> ks;
228 int sum = 0;
229 for (auto [k, v] : m)
230 {
231 ks.push_back(k);
232 sum += v;
233 }
234 EXPECT_EQ(ks, (std::vector<std::string>{"a", "b", "c"}));
235 EXPECT_EQ(sum, 6);
236
237 // Mutation through the iterator proxy.
238 for (auto [k, v] : m)
239 v *= 10;
240 EXPECT_EQ(m.at("a"), 10);
241 EXPECT_EQ(m.at("b"), 20);
242 EXPECT_EQ(m.at("c"), 30);
243
244 // Arrow access.
245 auto it = m.find("b");
246 ASSERT_NE(it, m.end());
247 EXPECT_EQ(it->first, "b");
248 it->second = 7;
249 EXPECT_EQ(m.at("b"), 7);
250}
251
253{
254 FlatMap<int, int> m = {{1, 10}, {2, 20}, {3, 30}, {4, 40}};
255
256 auto it = m.begin();
257 EXPECT_EQ(m.end() - it, 4);
258 EXPECT_EQ((it + 2)->first, 3);
259 EXPECT_EQ(it[3].second, 40);
260 ++it;
261 --it;
262 EXPECT_EQ(it->first, 1);
263 EXPECT_TRUE(it < m.end());
264
265 // Mutable-to-const iterator conversion.
267 EXPECT_EQ(cit->second, 10);
268}
269
271{
272 const FlatMap<int, int> m = {{10, 1}, {20, 2}, {30, 3}};
273
274 EXPECT_EQ(m.lower_bound(20)->first, 20);
275 EXPECT_EQ(m.lower_bound(25)->first, 30);
276 EXPECT_EQ(m.upper_bound(20)->first, 30);
277 EXPECT_EQ(m.lower_bound(31), m.end());
278
279 auto [lo, hi] = m.equal_range(20);
280 EXPECT_EQ(hi - lo, 1);
281 auto [lo2, hi2] = m.equal_range(15);
282 EXPECT_EQ(lo2, hi2);
283}
284
286{
287 FlatMap<std::string, int> m = {{"b", 2}, {"a", 1}, {"c", 3}};
288
289 auto ks = m.keys();
290 auto vs = m.values();
291 ASSERT_EQ(ks.size(), 3u);
292 ASSERT_EQ(vs.size(), 3u);
293 EXPECT_EQ(ks.get_first(), "a");
294 EXPECT_EQ(ks.get_last(), "c");
295 EXPECT_EQ(vs.get_first(), 1);
296 EXPECT_EQ(vs.get_last(), 3);
297}
298
300{
301 FlatMap<int, int> m = {{1, 1}, {2, 2}, {3, 3}};
302
303 EXPECT_TRUE(m.traverse([] (const int &, int &v) { v += 100; return true; }));
304 EXPECT_EQ(m.at(1), 101);
305
306 int visited = 0;
307 const FlatMap<int, int> &cm = m;
308 EXPECT_FALSE(cm.traverse([&visited] (const int &k, const int &)
309 {
310 ++visited;
311 return k < 2;
312 }));
313 EXPECT_EQ(visited, 2);
314}
315
317{
318 FlatMap<std::string, int> m = {{"x", 1}, {"y", 2}};
320 EXPECT_EQ(copy, m);
321
323 EXPECT_EQ(moved, m);
324
325 moved["z"] = 3;
326 EXPECT_NE(moved, m);
327
328 FlatMap<std::string, int> other = {{"q", 9}};
329 m.swap(other);
330 EXPECT_EQ(m.size(), 1u);
331 EXPECT_EQ(m.at("q"), 9);
332 EXPECT_EQ(other.size(), 2u);
333}
334
336{
338 = {{1, "one"}, {5, "five"}, {3, "three"}};
339 EXPECT_EQ(m.nth_key(0), 5);
340 EXPECT_EQ(m.nth_key(1), 3);
341 EXPECT_EQ(m.nth_key(2), 1);
342 EXPECT_EQ(m.at(3), "three");
343}
344
346{
347 FlatMap<int, int> m = {{2, 20}, {1, 10}, {3, 30}};
348 const int *kp = m.keys_data();
349 const int *vp = m.values_data();
350 for (size_t i = 0; i < m.size(); ++i)
351 EXPECT_EQ(vp[i], kp[i] * 10);
352}
353
354// Randomized parity test: FlatMap must behave exactly like std::map under
355// an arbitrary interleaving of subscripts, inserts, erases and lookups.
357{
358 std::mt19937 rng(20260702);
359 std::uniform_int_distribution<int> key_dist(0, 150);
360 std::uniform_int_distribution<int> val_dist(0, 1000000);
361 std::uniform_int_distribution<int> op_dist(0, 3);
362
364 std::map<int, int> ref;
365
366 for (int step = 0; step < 4000; ++step)
367 {
368 const int k = key_dist(rng);
369 const int v = val_dist(rng);
370 switch (op_dist(rng))
371 {
372 case 0:
373 fm[k] = v;
374 ref[k] = v;
375 break;
376 case 1:
377 EXPECT_EQ(fm.insert(k, v).second, ref.insert({k, v}).second);
378 break;
379 case 2:
380 EXPECT_EQ(fm.erase(k), ref.erase(k));
381 break;
382 default:
383 {
384 const auto it = ref.find(k);
385 if (it == ref.end())
386 EXPECT_FALSE(fm.contains(k));
387 else
388 EXPECT_EQ(fm.at(k), it->second);
389 }
390 break;
391 }
392 }
393
394 ASSERT_EQ(fm.size(), ref.size());
395 size_t i = 0;
396 for (const auto &[k, v] : ref)
397 {
398 EXPECT_EQ(fm.nth_key(i), k);
399 EXPECT_EQ(fm.nth_value(i), v);
400 ++i;
401 }
402}
Random-access proxy iterator over (key, value) entries.
Ordered map stored as two parallel sorted contiguous arrays.
iterator begin() noexcept
Iterator to the entry with the smallest key. O(1).
iterator end() noexcept
Iterator past the entry with the greatest key. O(1).
void swap(ODhashTable &other) noexcept
Definition tpl_odhash.H:420
constexpr bool contains(const Key &key) const noexcept
Alias for has().
Definition hashDry.H:425
constexpr size_t size() const noexcept
Returns the number of entries in the table.
Definition hashDry.H:619
constexpr bool is_empty() const noexcept
Checks if the table is empty.
Definition hashDry.H:624
DynList< Key > keys() const
Returns a list containing all keys in the table.
Definition hashDry.H:904
Key * insert(const Key &key)
Inserts a key into the hash table (copy version).
Definition hashDry.H:203
Key & find(const Key &key)
Finds a key and returns a reference to it.
Definition hashDry.H:438
iterator end() noexcept
Return an STL-compatible end iterator.
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
#define TEST(name)
static mt19937 rng
bool operator!=(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4053
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
bool operator==(const DynList< T > &l1, const DynList< T > &l2)
Equality operator for DynList.
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
Definition ahAlgo.H:584
and
Check uniqueness with explicit hash + equality functors.
Matrix< Trow, Tcol, NumType > operator*(const NumType &scalar, const Matrix< Trow, Tcol, NumType > &m)
Scalar-matrix multiplication (scalar * matrix).
Definition al-matrix.H:995
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
bool traverse(Operation &operation) noexcept(traverse_is_noexcept< Operation >())
Traverse the container via its iterator and performs a conditioned operation on each item.
Definition ah-dry.H:101
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
static int * k
Sorted-array map (Aleph::FlatMap), a cache-friendly ordered map.