Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
file_bplus_map_test.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7*/
8
9#include <gtest/gtest.h>
10
11#include <atomic>
12#include <chrono>
13#include <filesystem>
14#include <optional>
15#include <random>
16#include <string>
17#include <utility>
18#include <vector>
19
20#include <tpl_file_bplus_map.H>
21
22using namespace Aleph;
23
24namespace
25{
26 namespace fs = std::filesystem;
27
28 fs::path make_temp_path()
29 {
30 static std::atomic<unsigned long long> counter{0};
31 // Use a per-process random generator to avoid filename collisions
32 // across parallel processes.
33 static std::mt19937_64 rng{[] {
34 std::random_device rd;
35 const auto now_seed =
36 static_cast<unsigned long long>
37 (std::chrono::steady_clock::now().time_since_epoch().count());
38 return std::mt19937_64{now_seed ^
39 (static_cast<unsigned long long>(rd()) << 1u)};
40 }()};
41
42 const auto now = std::chrono::steady_clock::now().time_since_epoch().count();
43 std::uniform_int_distribution<unsigned long long> dist;
44 const auto random_value = dist(rng);
45
46 const auto id = std::to_string(now) + "_" +
47 std::to_string(random_value) + "_" +
48 std::to_string(counter++);
49
50 const fs::path dir = fs::temp_directory_path() / "aleph_file_bplusmap_tests";
51 fs::create_directories(dir);
52 return dir / (id + ".idx");
53 }
54
55 struct TempFile
56 {
57 fs::path path;
58
59 explicit TempFile(fs::path p) : path(std::move(p)) {}
60
61 ~TempFile()
62 {
63 std::error_code ec;
64 fs::remove(path, ec);
65 fs::remove(path.string() + ".wal", ec);
66 fs::remove(path.string() + ".wal.tmp", ec);
67 fs::remove(path.string() + ".journal", ec);
68 fs::remove(path.string() + ".journal.tmp", ec);
69 fs::remove(path.string() + ".lock", ec);
70 }
71 };
72
73 template <typename T>
74 std::vector<T> to_vector(const Array<T> & arr)
75 {
76 std::vector<T> out;
77 out.reserve(arr.size());
78 for (size_t i = 0; i < arr.size(); ++i)
79 out.push_back(arr[i]);
80 return out;
81 }
82} // namespace
83
85{
86 TempFile tmp(make_temp_path());
87
88 {
89 File_BPlus_Map<int, int, Aleph::less<int>, 3> map(tmp.path.string(), false);
90 EXPECT_TRUE(map.insert(10, 100));
91 EXPECT_TRUE(map.insert(20, 200));
92 EXPECT_TRUE(map.insert(30, 300));
93 EXPECT_TRUE(map.insert(40, 400));
94 EXPECT_TRUE(map.insert(50, 500));
95 EXPECT_EQ(to_vector(map.range(15, 45)),
96 (std::vector<std::pair<int, int>>{{20, 200}, {30, 300}, {40, 400}}));
97 EXPECT_TRUE(map.verify());
98 map.sync();
99 }
100
102 tmp.path.string(),
104 EXPECT_TRUE(reopened.is_read_only());
105 EXPECT_EQ(to_vector(reopened.range(10, 30)),
106 (std::vector<std::pair<int, int>>{{10, 100}, {20, 200}, {30, 300}}));
107}
108
110{
111 TempFile tmp(make_temp_path());
112
113 File_BPlus_Map<int, long, Aleph::less<int>, 3> map(tmp.path.string(), false);
114 EXPECT_TRUE(map.insert(5, 50));
115 EXPECT_TRUE(map.insert(15, 150));
116 EXPECT_TRUE(map.insert(25, 250));
117 EXPECT_TRUE(map.insert(35, 350));
118 EXPECT_FALSE(map.insert_or_assign(25, 255));
119 EXPECT_EQ(map.at(25), 255);
120
121 EXPECT_EQ(map.lower_bound(16), (std::optional<std::pair<int, long>>{{25, 255}}));
122 EXPECT_EQ(map.upper_bound(25), (std::optional<std::pair<int, long>>{{35, 350}}));
123 EXPECT_EQ(to_vector(map.items()),
124 (std::vector<std::pair<int, long>>{{5, 50}, {15, 150}, {25, 255}, {35, 350}}));
125
126 EXPECT_TRUE(map.remove(15));
127 EXPECT_FALSE(map.contains(15));
128 EXPECT_EQ(to_vector(map.values()), (std::vector<long>{50, 255, 350}));
129 EXPECT_TRUE(map.verify());
130}
131
133{
134 TempFile tmp(make_temp_path());
135
136 File_BPlus_Map<int, int, Aleph::less<int>, 3> map(tmp.path.string(), false);
137 for (const auto & [key, value] : std::vector<std::pair<int, int>>{
138 {101, 750}, {105, 920}, {110, 875}, {120, 990}, {130, 1010}})
139 EXPECT_TRUE(map.insert(key, value));
140
141 std::vector<std::pair<int, int>> all_items;
142 for (auto it = map.get_it(); it.has_curr(); it.next_ne())
143 all_items.push_back(it.get_curr());
145 (std::vector<std::pair<int, int>>{
146 {101, 750}, {105, 920}, {110, 875}, {120, 990}, {130, 1010}}));
147
148 std::vector<std::pair<int, int>> band;
149 auto it = map.get_range_it(104, 120);
150 ASSERT_TRUE(it.has_curr());
151 EXPECT_EQ(it.get_key(), 105);
152 EXPECT_EQ(it.get_value(), 920);
153 for (; it.has_curr(); it.next())
154 band.push_back(it.get_curr());
155
157 (std::vector<std::pair<int, int>>{
158 {105, 920}, {110, 875}, {120, 990}}));
159}
160
162{
163 TempFile tmp(make_temp_path());
166
167 {
169 key_codec, value_codec> map(tmp.path.string(), false);
170 EXPECT_TRUE(map.insert("apple", "green"));
171 EXPECT_TRUE(map.insert("banana", "yellow"));
172 EXPECT_TRUE(map.insert("kiwi", "brown fuzz"));
173 EXPECT_FALSE(map.insert_or_assign("banana", "ripe yellow"));
174 EXPECT_EQ(map.at("banana"), "ripe yellow");
175 EXPECT_EQ(to_vector(map.range(std::string("banana"), std::string("kiwi"))),
176 (std::vector<std::pair<std::string, std::string>>{
177 {"banana", "ripe yellow"}, {"kiwi", "brown fuzz"}}));
178 EXPECT_TRUE(map.verify());
179 map.sync();
180 }
181
183 key_codec, value_codec> reopened(
184 tmp.path.string(),
185 File_BPlus_Map<std::string, std::string, Aleph::less<std::string>, 3,
186 key_codec, value_codec>::Read_Only);
187 EXPECT_TRUE(reopened.verify());
189 (std::vector<std::pair<std::string, std::string>>{
190 {"apple", "green"},
191 {"banana", "ripe yellow"},
192 {"kiwi", "brown fuzz"}}));
193
194 std::vector<std::pair<std::string, std::string>> lazy_items;
195 for (auto it = reopened.get_it(); it.has_curr(); it.next())
196 lazy_items.push_back(it.get_curr());
198}
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:351
bool has_curr() const noexcept
Return whether the iterator still points to an item.
Persistent ordered map backed by a paged File_BPlus_Tree.
Iterator get_range_it(const Key &first, const Key &last) const
Return a lazy iterator over an inclusive key range.
std::optional< value_type > lower_bound(const Key &key) const
Return the first key/value pair whose key is not less than key.
Array< value_type > range(const Key &first, const Key &last) const
Collect all key/value pairs in the inclusive key range.
Iterator get_it() const noexcept
Return a lazy iterator over all items in key order.
Value at(const Key &key) const
Return the mapped value associated with a key.
bool insert_or_assign(const Key &key, const Value &value)
Insert or overwrite a key/value pair.
bool insert(const Key &key, const Value &value)
Insert a new key/value pair if the key is not present.
#define TEST(name)
static mt19937 rng
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::vector< typename C::Item_Type > to_vector(const C &c)
Convert a container to a std::vector.
Definition ah-convert.H:238
STL namespace.
static long counter
Definition test-splice.C:35
Persistent key/value map built on top of Aleph::File_BPlus_Tree.