Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_file_bplus_map.H
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 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
41# ifndef TPL_FILE_BPLUS_MAP_H
42# define TPL_FILE_BPLUS_MAP_H
43
44# include <array>
45# include <bit>
46# include <cstddef>
47# include <cstring>
48# include <optional>
49# include <ostream>
50# include <string>
51# include <type_traits>
52# include <utility>
53
54# include <ah-concepts.H>
55# include <ah-errors.H>
56# include <tpl_array.H>
57# include <tpl_file_bplus_tree.H>
58
59namespace Aleph
60{
94 template <typename Key,
95 typename Value,
96 class Compare = Aleph::less<Key>,
97 size_t MinDegree = 16,
102 {
105
106 struct Record
107 {
108 std::array<unsigned char,
109 key_codec::encoded_size + value_codec::encoded_size> bytes = {};
110
111 friend std::ostream & operator << (std::ostream & out, const Record &)
112 {
113 return out << "<record>";
114 }
115
116 [[nodiscard]] Key get_key() const
117 {
118 return key_codec::decode(bytes.data());
119 }
120
122 {
123 return value_codec::decode(bytes.data() + key_codec::encoded_size);
124 }
125 };
126
128 {
129 static constexpr std::uint32_t storage_id =
131 key_codec::storage_id),
132 value_codec::storage_id);
133 static constexpr size_t encoded_size =
134 key_codec::encoded_size + value_codec::encoded_size;
135
136 static void encode(const Record & record, unsigned char * out) noexcept
137 {
138 std::memcpy(out, record.bytes.data(), record.bytes.size());
139 }
140
141 [[nodiscard]] static Record decode(const unsigned char * in) noexcept
142 {
143 Record record;
144 std::memcpy(record.bytes.data(), in, record.bytes.size());
145 return record;
146 }
147
148 [[nodiscard]] static std::uint32_t add_to_crc(
149 const std::uint32_t crc,
150 const Record & record) noexcept
151 {
152 return detail::crc32_add_bytes(crc, record.bytes.data(),
153 record.bytes.size());
154 }
155 };
156
158 {
159 Compare cmp;
160
161 bool operator () (const Record & lhs, const Record & rhs) const
162 {
163 return cmp(lhs.get_key(), rhs.get_key());
164 }
165 };
166
169
171 "File_BPlus_Map requires a fixed-size key codec");
173 "File_BPlus_Map requires a fixed-size mapped-value codec");
174 static_assert(std::is_trivially_copyable_v<Record>,
175 "File_BPlus_Map requires trivially copyable records");
176
178
179 [[nodiscard]] static Record make_probe(const Key & key)
180 {
181 Record record;
182 key_codec::encode(key, record.bytes.data());
183 return record;
184 }
185
186 [[nodiscard]] static Record make_record(const Key & key,
187 const Value & value)
188 {
189 Record record;
190 key_codec::encode(key, record.bytes.data());
191 value_codec::encode(value, record.bytes.data() + key_codec::encoded_size);
192 return record;
193 }
194
195 [[nodiscard]] static std::pair<Key, Value>
196 to_pair(const Record & record)
197 {
198 return std::pair<Key, Value>(record.get_key(), record.get_value());
199 }
200
203 {
205 out.reserve(records.size() == 0 ? 1 : records.size());
206 for (size_t i = 0; i < records.size(); ++i)
207 out.append(to_pair(records[i]));
208 return out;
209 }
210
211 [[nodiscard]] bool equals_key(const Key & lhs, const Key & rhs) const
212 {
213 const auto & cmp = tree_.key_comp().cmp;
214 return not cmp(lhs, rhs) and not cmp(rhs, lhs);
215 }
216
217 [[nodiscard]] std::optional<Record> find_record(const Key & key) const
218 {
219 const auto probe = make_probe(key);
220 auto candidate = tree_.lower_bound(probe);
221 if (candidate.has_value() and equals_key(candidate->get_key(), key))
222 return candidate;
223 return std::nullopt;
224 }
225
226 public:
227 using key_type = Key;
229 using value_type = std::pair<Key, Value>;
232
233 static constexpr auto Read_Write = tree_type::Read_Write;
234 static constexpr auto Read_Only = tree_type::Read_Only;
235
243 {
245
246 public:
251
258
264 {
265 return it_.has_curr();
266 }
267
273 {
274 return to_pair(it_.get_curr());
275 }
276
281 [[nodiscard]] Key get_key() const
282 {
283 return it_.get_curr().get_key();
284 }
285
291 {
292 return it_.get_curr().get_value();
293 }
294
298 void next_ne()
299 {
300 it_.next_ne();
301 }
302
306 void next()
307 {
308 next_ne();
309 }
310 };
311
319 explicit Gen_File_BPlus_Map(std::string file_path,
320 const bool auto_sync = true,
321 const Compare & cmp = Compare())
323
332 explicit Gen_File_BPlus_Map(std::string file_path,
334 const bool auto_sync = true,
335 const Compare & cmp = Compare())
337
345 explicit Gen_File_BPlus_Map(const char * file_path,
346 const bool auto_sync = true,
347 const Compare & cmp = Compare())
349
358 explicit Gen_File_BPlus_Map(const char * file_path,
360 const bool auto_sync = true,
361 const Compare & cmp = Compare())
363
366
369
372
375
380 [[nodiscard]] const std::string & file_path() const noexcept
381 {
382 return tree_.file_path();
383 }
384
393
399 {
400 return tree_.is_read_only();
401 }
402
408 {
409 return tree_.auto_sync_enabled();
410 }
411
416 void set_auto_sync(const bool enabled) noexcept
417 {
418 tree_.set_auto_sync(enabled);
419 }
420
425 [[nodiscard]] const Compare & key_comp() const noexcept
426 {
427 return tree_.key_comp().cmp;
428 }
429
434 [[nodiscard]] bool empty() const noexcept { return tree_.empty(); }
435
440 [[nodiscard]] size_t size() const noexcept { return tree_.size(); }
441
446 [[nodiscard]] size_t height() const noexcept { return tree_.height(); }
447
453 {
454 return tree_.page_size_bytes();
455 }
456
462 {
463 return tree_.page_count();
464 }
465
471 {
472 return tree_.checkpoint_sequence();
473 }
474
478 void sync() const
479 {
480 tree_.sync();
481 }
482
486 void checkpoint() const
487 {
489 }
490
494 void reload()
495 {
496 tree_.reload();
497 }
498
502 void clear()
503 {
504 tree_.clear();
505 }
506
512 [[nodiscard]] bool contains(const Key & key) const
513 {
514 return find_record(key).has_value();
515 }
516
522 [[nodiscard]] bool search(const Key & key) const
523 {
524 return contains(key);
525 }
526
532 [[nodiscard]] std::optional<Value> find(const Key & key) const
533 {
534 const auto record = find_record(key);
535 if (not record.has_value())
536 return std::nullopt;
537 return record->get_value();
538 }
539
546 [[nodiscard]] Value at(const Key & key) const
547 {
548 const auto value = find(key);
549 ah_domain_error_if(not value.has_value())
550 << "File_BPlus_Map::at(): key not found";
551 return *value;
552 }
553
561 bool insert(const Key & key, const Value & value)
562 {
563 return tree_.insert(make_record(key, value));
564 }
565
585 bool insert_or_assign(const Key & key, const Value & value)
586 {
587 const auto probe = make_probe(key);
588 const auto record = make_record(key, value);
589 if (tree_.insert(record))
590 return true;
592 << "File_BPlus_Map::insert_or_assign(): internal replace failed";
594 << "File_BPlus_Map::insert_or_assign(): internal reinsert failed";
595 return false;
596 }
597
603 bool remove(const Key & key)
604 {
605 return tree_.remove(make_probe(key));
606 }
607
612 [[nodiscard]] std::optional<value_type> min_item() const
613 {
614 const auto record = tree_.min_key();
615 if (not record.has_value())
616 return std::nullopt;
617 return to_pair(*record);
618 }
619
624 [[nodiscard]] std::optional<value_type> max_item() const
625 {
626 const auto record = tree_.max_key();
627 if (not record.has_value())
628 return std::nullopt;
629 return to_pair(*record);
630 }
631
637 [[nodiscard]] std::optional<value_type> lower_bound(const Key & key) const
638 {
639 const auto record = tree_.lower_bound(make_probe(key));
640 if (not record.has_value())
641 return std::nullopt;
642 return to_pair(*record);
643 }
644
650 [[nodiscard]] std::optional<value_type> upper_bound(const Key & key) const
651 {
652 const auto record = tree_.upper_bound(make_probe(key));
653 if (not record.has_value())
654 return std::nullopt;
655 return to_pair(*record);
656 }
657
665 [[nodiscard]] Array<value_type> range(const Key & first, const Key & last) const
666 {
667 return to_pairs(tree_.range(make_probe(first), make_probe(last)));
668 }
669
675 {
677 const auto records = tree_.keys();
678 out.reserve(records.size() == 0 ? 1 : records.size());
679 for (size_t i = 0; i < records.size(); ++i)
680 out.append(records[i].get_key());
681 return out;
682 }
683
689 {
691 const auto records = tree_.keys();
692 out.reserve(records.size() == 0 ? 1 : records.size());
693 for (size_t i = 0; i < records.size(); ++i)
694 out.append(records[i].get_value());
695 return out;
696 }
697
703 {
704 return to_pairs(tree_.keys());
705 }
706
712 {
713 return Iterator(tree_.get_it());
714 }
715
722 [[nodiscard]] Iterator get_range_it(const Key & first, const Key & last) const
723 {
724 return Iterator(tree_.get_range_it(make_probe(first), make_probe(last)));
725 }
726
731 [[nodiscard]] bool verify() const
732 {
733 return tree_.verify();
734 }
735 };
736
738 template <typename Key,
739 typename Value,
740 class Compare = Aleph::less<Key>,
741 size_t MinDegree = 16,
746} // namespace Aleph
747
748# endif // TPL_FILE_BPLUS_MAP_H
C++20 concepts for constraining comparison functors.
Exception handling system with formatted messages for Aleph-w.
#define ah_runtime_error_unless(C)
Throws std::runtime_error if condition does NOT hold.
Definition ah-errors.H:250
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
void reserve(size_t cap)
Reserves cap cells into the array.
Definition tpl_array.H:315
Lazy iterator over ordered key/value pairs.
value_type get_curr() const
Return the current key/value pair.
void next()
Synonym for next_ne().
Value get_value() const
Return the current mapped value.
bool has_curr() const noexcept
Return whether the iterator still points to an item.
Iterator() noexcept=default
Construct an exhausted iterator.
void next_ne()
Advance to the next item.
Key get_key() const
Return the current key.
Persistent ordered map backed by a paged File_BPlus_Tree.
static Record make_record(const Key &key, const Value &value)
size_t page_size_bytes() const noexcept
Return the serialized page size of the backing tree.
Gen_File_BPlus_Tree< Record, Record_Compare, MinDegree, Record_Codec > tree_impl_type
Array< Value > values() const
Materialize all mapped values in key order.
Gen_File_BPlus_Map(Gen_File_BPlus_Map &&)=delete
Moving is disabled.
Iterator get_range_it(const Key &first, const Key &last) const
Return a lazy iterator over an inclusive key range.
static constexpr auto Read_Only
const Compare & key_comp() const noexcept
Return the key comparator.
bool remove(const Key &key)
Remove a key and its mapped value, if present.
std::optional< Record > find_record(const Key &key) const
Gen_File_BPlus_Map(std::string file_path, const bool auto_sync=true, const Compare &cmp=Compare())
Open or create a persistent B+ Tree map for read-write access.
std::optional< value_type > lower_bound(const Key &key) const
Return the first key/value pair whose key is not less than key.
std::optional< value_type > min_item() const
Return the smallest stored key/value pair.
Array< value_type > range(const Key &first, const Key &last) const
Collect all key/value pairs in the inclusive key range.
size_t size() const noexcept
Return the number of stored key/value pairs.
open_mode_type open_mode() const noexcept
Return the open mode.
void reload()
Discard unsynchronized changes and reload the file.
Array< Key > keys() const
Materialize all keys in sorted order.
Iterator get_it() const noexcept
Return a lazy iterator over all items in key order.
size_t page_count() const noexcept
Return the number of allocated pages.
Gen_File_BPlus_Map & operator=(const Gen_File_BPlus_Map &)=delete
Assignment is disabled.
std::optional< Value > find(const Key &key) const
Return the mapped value associated with a key, if any.
Gen_File_BPlus_Map(const char *file_path, const open_mode_type open_mode, const bool auto_sync=true, const Compare &cmp=Compare())
Open or create a persistent B+ Tree map with an explicit mode.
void sync() const
Flush pending changes to the backing file.
Value at(const Key &key) const
Return the mapped value associated with a key.
bool search(const Key &key) const
Synonym for contains().
bool contains(const Key &key) const
Return whether a key exists.
bool auto_sync_enabled() const noexcept
Return whether automatic synchronization is enabled.
void clear()
Remove every key/value pair from the map.
bool empty() const noexcept
Return whether the map is empty.
size_t height() const noexcept
Return the current tree height.
bool is_read_only() const noexcept
Return whether the map handle is read-only.
typename tree_type::open_mode_type open_mode_type
static Array< std::pair< Key, Value > > to_pairs(const Array< Record > &records)
std::optional< value_type > max_item() const
Return the largest stored key/value pair.
void set_auto_sync(const bool enabled) noexcept
Enable or disable automatic synchronization.
std::uint64_t checkpoint_sequence() const noexcept
Return the latest durable checkpoint sequence.
bool verify() const
Verify the structural invariants of the backing tree.
Gen_File_BPlus_Map(const Gen_File_BPlus_Map &)=delete
Copying is disabled.
bool equals_key(const Key &lhs, const Key &rhs) const
bool insert_or_assign(const Key &key, const Value &value)
Insert or overwrite a key/value pair.
Gen_File_BPlus_Map(const char *file_path, const bool auto_sync=true, const Compare &cmp=Compare())
Open or create a persistent B+ Tree map for read-write access.
const std::string & file_path() const noexcept
Return the file path.
bool insert(const Key &key, const Value &value)
Insert a new key/value pair if the key is not present.
Gen_File_BPlus_Map(std::string file_path, const open_mode_type open_mode, const bool auto_sync=true, const Compare &cmp=Compare())
Open or create a persistent B+ Tree map with an explicit mode.
void checkpoint() const
Synonym for sync().
Array< value_type > items() const
Materialize all key/value pairs in sorted order.
static Record make_probe(const Key &key)
static std::pair< Key, Value > to_pair(const Record &record)
static constexpr auto Read_Write
std::pair< Key, Value > value_type
std::optional< value_type > upper_bound(const Key &key) const
Return the first key/value pair whose key is greater than key.
Lazy iterator over ordered keys stored in leaf pages.
void next_ne()
Advance to the next key.
bool has_curr() const noexcept
Return whether the iterator still points to a key.
const Key & get_curr() const
Return the current key.
Persistent page-managed B+ Tree stored in a single binary file.
const Compare & key_comp() const noexcept
Return the comparison object.
bool is_read_only() const noexcept
Return whether this handle is read-only.
bool insert(const Key &key)
Insert a key if it is not already present.
bool empty() const noexcept
Return whether the tree has no keys.
const std::string & file_path() const noexcept
Return the backing file path.
Iterator get_it() const noexcept
Return a lazy iterator over the full key order.
Paged_File_Open_Mode open_mode_type
File opening mode type.
Paged_File_Open_Mode open_mode() const noexcept
Return the access mode used to open the file.
std::optional< Key > max_key() const
Return the maximum key, if any.
std::uint64_t checkpoint_sequence() const noexcept
Return the durable checkpoint sequence stored in the backing file.
void sync() const
Flush the current tree image using redo WAL or full-image fallback.
bool auto_sync_enabled() const noexcept
Return whether automatic synchronization is enabled.
bool verify() const
Verify structural B+ Tree invariants across cached pages.
bool remove(const Key &key)
Remove a key if present.
static constexpr auto Read_Only
void reload()
Discard unsynchronized changes and reload pages from disk.
void clear()
Remove every key from the tree.
std::optional< Key > min_key() const
Return the minimum key, if any.
size_t size() const noexcept
Return the number of stored keys.
Array< Key > range(const Key &first, const Key &last) const
Collect all keys in the inclusive range [first, last].
void set_auto_sync(const bool enabled) noexcept
Enable or disable automatic flushing of dirty pages.
static constexpr auto Read_Write
size_t page_count() const noexcept
Return the number of allocated pages currently tracked.
void checkpoint() const
Synonym for sync().
Array< Key > keys() const
Materialize the tree contents in sorted order.
Iterator get_range_it(const Key &first, const Key &last) const
Return a lazy iterator over an inclusive key range.
std::optional< Key > upper_bound(const Key &key) const
Return the first key strictly greater than key.
size_t page_size_bytes() const noexcept
Return the fixed serialized page size.
size_t height() const noexcept
Return the current height of the paged tree.
std::optional< Key > lower_bound(const Key &key) const
Return the first key not less than key.
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4118
std::uint32_t crc32_add_bytes(std::uint32_t crc, const void *data, const size_t size) noexcept
constexpr std::uint32_t mix_codec_id(const std::uint32_t seed, const std::uint32_t value) noexcept
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
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.
STL namespace.
static Record decode(const unsigned char *in) noexcept
static constexpr std::uint32_t storage_id
static std::uint32_t add_to_crc(const std::uint32_t crc, const Record &record) noexcept
static void encode(const Record &record, unsigned char *out) noexcept
bool operator()(const Record &lhs, const Record &rhs) const
std::array< unsigned char, key_codec::encoded_size+value_codec::encoded_size > bytes
friend std::ostream & operator<<(std::ostream &out, const Record &)
Dynamic array container with automatic resizing.
Page-managed persistent B+ Tree with file-backed storage.