Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
persistent_treap_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
35#include <gtest/gtest.h>
36
38
39#include <map>
40#include <memory>
41#include <random>
42#include <set>
43#include <stdexcept>
44#include <string>
45#include <vector>
46
47using namespace Aleph;
48
49namespace
50{
51 struct DirectionalIntCompare
52 {
53 bool reverse = false;
54
55 bool operator () (const int lhs, const int rhs) const noexcept
56 {
57 return reverse ? lhs > rhs : lhs < rhs;
58 }
59 };
60
61 template <class ArrayType>
62 std::vector<typename ArrayType::Item_Type> to_vector(const ArrayType &array)
63 {
64 std::vector<typename ArrayType::Item_Type> out;
65 out.reserve(array.size());
66 for (size_t i = 0; i < array.size(); ++i)
67 out.push_back(array[i]);
68 return out;
69 }
70}
71
73{
75 auto one = empty.insert(10);
76 auto two = one.insert(5).insert(20);
77 auto erased = two.erase(10);
78
79 EXPECT_TRUE(empty.is_empty());
80 EXPECT_FALSE(empty.contains(10));
81
82 EXPECT_EQ(one.size(), 1u);
83 EXPECT_TRUE(one.contains(10));
84 EXPECT_FALSE(one.contains(5));
85
86 EXPECT_EQ(two.size(), 3u);
87 EXPECT_TRUE(two.contains(5));
88 EXPECT_TRUE(two.contains(10));
89 EXPECT_TRUE(two.contains(20));
90
91 EXPECT_EQ(erased.size(), 2u);
92 EXPECT_FALSE(erased.contains(10));
93 EXPECT_TRUE(two.contains(10)); // old version unchanged
94
95 EXPECT_TRUE(empty.verify());
96 EXPECT_TRUE(one.verify());
97 EXPECT_TRUE(two.verify());
98 EXPECT_TRUE(erased.verify());
99}
100
102{
104 auto one = set.insert(7);
105 auto duplicate = one.insert(7);
106 auto missing = duplicate.erase(99);
107
108 EXPECT_EQ(one.size(), 1u);
109 EXPECT_EQ(duplicate.size(), 1u);
110 EXPECT_EQ(missing.size(), 1u);
111 EXPECT_TRUE(missing.contains(7));
112 EXPECT_TRUE(missing.verify());
113}
114
116{
118 for (int x : {4, 1, 7, 3, 9, 2})
119 set = set.insert(x);
120
121 EXPECT_EQ(to_vector(set.keys()), (std::vector<int>{1, 2, 3, 4, 7, 9}));
122 EXPECT_TRUE(set.verify());
123}
124
126{
128 for (int i = 0; i < 10; ++i)
129 set = set.insert(i);
130
131 auto [left, right] = set.split(5);
132 EXPECT_EQ(to_vector(left.keys()), (std::vector<int>{0, 1, 2, 3, 4}));
133 EXPECT_EQ(to_vector(right.keys()), (std::vector<int>{5, 6, 7, 8, 9}));
134
135 auto joined = left.join(right);
136 EXPECT_EQ(to_vector(joined.keys()), (std::vector<int>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}));
137 EXPECT_TRUE(left.verify());
138 EXPECT_TRUE(right.verify());
139 EXPECT_TRUE(joined.verify());
140}
141
143{
144 auto left = PersistentTreapSet<int>().insert(1).insert(3);
145 auto right = PersistentTreapSet<int>().insert(3).insert(5);
146
147 EXPECT_THROW((void)left.join(right), std::domain_error);
148}
149
151{
152 PersistentTreapSet<int, DirectionalIntCompare> left{DirectionalIntCompare{false}};
153 left = left.insert(1).insert(2);
154
155 PersistentTreapSet<int, DirectionalIntCompare> right{DirectionalIntCompare{true}};
156 right = right.insert(6).insert(5).insert(4);
157
158 ASSERT_TRUE(left.verify());
159 ASSERT_TRUE(right.verify());
160 EXPECT_THROW((void)left.join(right), std::domain_error);
161}
162
164{
165 std::mt19937 rng(0x5EEDu);
166 std::uniform_int_distribution<int> key_dist(0, 80);
167 std::uniform_int_distribution<int> op_dist(0, 1);
168
170 std::set<int> reference;
171 std::vector<PersistentTreapSet<int>> old_subjects;
172 std::vector<std::set<int>> old_references;
173
174 for (int iter = 0; iter < 1200; ++iter)
175 {
176 if (iter % 37 == 0)
177 {
178 old_subjects.push_back(subject);
179 old_references.push_back(reference);
180 }
181
182 const int key = key_dist(rng);
183 if (op_dist(rng) == 0)
184 {
185 subject = subject.insert(key);
186 reference.insert(key);
187 }
188 else
189 {
190 subject = subject.erase(key);
191 reference.erase(key);
192 }
193
194 ASSERT_TRUE(subject.verify());
195 EXPECT_EQ(subject.size(), reference.size());
197 std::vector<int>(reference.begin(), reference.end()));
198 }
199
200 for (size_t i = 0; i < old_subjects.size(); ++i)
202 std::vector<int>(old_references[i].begin(), old_references[i].end()));
203}
204
206{
208 auto one = empty.insert(1, std::string("one"));
209 auto two = one.insert(2, std::string("two"));
210 auto reassigned = two.insert_or_assign(1, std::string("uno"));
211 auto erased = reassigned.erase(2);
212
213 ASSERT_NE(one.find(1), nullptr);
214 EXPECT_EQ(*one.find(1), "one");
215 EXPECT_EQ(one.find(2), nullptr);
216
217 ASSERT_NE(two.find(2), nullptr);
218 EXPECT_EQ(*two.find(2), "two");
219 EXPECT_EQ(*two.find(1), "one");
220
221 EXPECT_EQ(*reassigned.find(1), "uno");
222 EXPECT_EQ(*two.find(1), "one"); // old version unchanged
223
224 EXPECT_FALSE(erased.contains(2));
225 EXPECT_TRUE(reassigned.contains(2));
226 EXPECT_TRUE(empty.verify());
227 EXPECT_TRUE(one.verify());
228 EXPECT_TRUE(two.verify());
229 EXPECT_TRUE(reassigned.verify());
230 EXPECT_TRUE(erased.verify());
231}
232
234{
236 .insert(4, std::string("four"))
237 .insert(4, std::string("cuatro"));
238
239 ASSERT_NE(map.find(4), nullptr);
240 EXPECT_EQ(*map.find(4), "four");
241 EXPECT_EQ(map.size(), 1u);
242 EXPECT_TRUE(map.verify());
243}
244
246{
248 for (int i = 0; i < 6; ++i)
249 map = map.insert(i, std::to_string(i));
250
251 auto [left, right] = map.split(3);
252 EXPECT_EQ(to_vector(left.keys()), (std::vector<int>{0, 1, 2}));
253 EXPECT_EQ(to_vector(right.keys()), (std::vector<int>{3, 4, 5}));
254
256 auto items = joined.items();
257 ASSERT_EQ(items.size(), 6u);
258 for (size_t i = 0; i < items.size(); ++i)
259 {
260 EXPECT_EQ(items[i].first, static_cast<int>(i));
261 EXPECT_EQ(items[i].second, std::to_string(i));
262 }
263 EXPECT_TRUE(joined.verify());
264}
265
267{
268 PersistentTreapMap<int, std::string, DirectionalIntCompare> left{DirectionalIntCompare{false}};
269 left = left.insert(1, std::string("one")).insert(2, std::string("two"));
270
271 PersistentTreapMap<int, std::string, DirectionalIntCompare> right{DirectionalIntCompare{true}};
272 right = right.insert(6, std::string("six"))
273 .insert(5, std::string("five"))
274 .insert(4, std::string("four"));
275
276 ASSERT_TRUE(left.verify());
277 ASSERT_TRUE(right.verify());
278 EXPECT_THROW((void)left.join(right), std::domain_error);
279}
280
282{
284 auto one = map.insert(1, std::make_unique<int>(10));
285 auto two = one.insert_or_assign(1, std::make_unique<int>(20));
286 auto three = two.insert(2, std::make_unique<int>(30));
287
288 ASSERT_NE(one.find(1), nullptr);
289 ASSERT_NE(two.find(1), nullptr);
290 ASSERT_NE(three.find(2), nullptr);
291 EXPECT_EQ(**one.find(1), 10);
292 EXPECT_EQ(**two.find(1), 20);
293 EXPECT_EQ(**three.find(2), 30);
294 EXPECT_TRUE(one.verify());
295 EXPECT_TRUE(two.verify());
296 EXPECT_TRUE(three.verify());
297}
298
300{
301 std::mt19937 rng(0xBADC0DEu);
302 std::uniform_int_distribution<int> key_dist(0, 60);
303 std::uniform_int_distribution<int> value_dist(-1000, 1000);
304 std::uniform_int_distribution<int> op_dist(0, 2);
305
307 std::map<int, int> reference;
308 std::vector<PersistentTreapMap<int, int>> old_subjects;
309 std::vector<std::map<int, int>> old_references;
310
311 for (int iter = 0; iter < 1500; ++iter)
312 {
313 if (iter % 41 == 0)
314 {
315 old_subjects.push_back(subject);
316 old_references.push_back(reference);
317 }
318
319 const int key = key_dist(rng);
320 const int op = op_dist(rng);
321 if (op == 0)
322 {
323 const int value = value_dist(rng);
324 subject = subject.insert(key, value);
325 reference.insert({key, value});
326 }
327 else if (op == 1)
328 {
329 const int value = value_dist(rng);
330 subject = subject.insert_or_assign(key, value);
331 reference[key] = value;
332 }
333 else
334 {
335 subject = subject.erase(key);
336 reference.erase(key);
337 }
338
339 ASSERT_TRUE(subject.verify());
340 EXPECT_EQ(subject.size(), reference.size());
341 for (const auto &[k, v] : reference)
342 {
343 ASSERT_NE(subject.find(k), nullptr);
344 EXPECT_EQ(*subject.find(k), v);
345 }
346 }
347
348 for (size_t i = 0; i < old_subjects.size(); ++i)
349 {
351 for (const auto &[k, v] : old_references[i])
352 {
353 ASSERT_NE(old_subjects[i].find(k), nullptr);
354 EXPECT_EQ(*old_subjects[i].find(k), v);
355 }
356 }
357}
size_t size_t int32_t value
Definition ca-c-api.h:116
size_t size_t int32_t * out
Definition ca-c-api.h:120
Immutable ordered map backed by a path-copying treap.
std::pair< PersistentTreapMap, PersistentTreapMap > split(const Key &pivot) const
Split this version around pivot.
and std::constructible_from< T, VArg && > PersistentTreapMap insert_or_assign(KArg &&key, VArg &&value) const
Return a new version with key assigned to value.
PersistentTreapMap erase(const Key &key) const
Return a new version without key.
static PersistentTreapMap join(const PersistentTreapMap &left, const PersistentTreapMap &right)
Join two ordered, non-overlapping map versions.
bool verify() const
Verify treap, BST and cached-size invariants.
and std::constructible_from< T, VArg && > PersistentTreapMap insert(KArg &&key, VArg &&value) const
Return a new version with a binding inserted if absent.
Immutable ordered set backed by a path-copying treap.
Array< Key > keys() const
Return all keys in sorted order.
bool verify() const
Verify treap, BST and cached-size invariants.
PersistentTreapSet erase(const Key &key) const
Return a new version without key.
PersistentTreapSet insert(const Key &key) const
Return a new version with key inserted by copy.
std::pair< PersistentTreapSet, PersistentTreapSet > split(const Key &pivot) const
Split this version around pivot.
bool is_empty() const noexcept
Return true when the set has no keys.
bool contains(const Key &key) const
Test whether key is present.
#define TEST(name)
static mt19937 rng
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
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
void reverse(Itor beg, Itor end)
Reverse elements in a range.
Definition ahAlgo.H:1094
size_t size(Node *root) noexcept
Itor find(const Itor &beg, const Itor &end, const T &value)
Find the first element equal to a value.
Definition ahAlgo.H:230
std::vector< typename C::Item_Type > to_vector(const C &c)
Convert a container to a std::vector.
Definition ah-convert.H:238
int keys[]
static int * k
Immutable path-copying treap set and map.