-
Notifications
You must be signed in to change notification settings - Fork 4
/
art_internal.hpp
231 lines (176 loc) · 6.4 KB
/
art_internal.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
// Copyright 2019-2024 Laurynas Biveinis
#ifndef UNODB_DETAIL_ART_INTERNAL_HPP
#define UNODB_DETAIL_ART_INTERNAL_HPP
#include "global.hpp"
// IWYU pragma: no_include <__fwd/ostream.h>
// IWYU pragma: no_include <_string.h>
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <iosfwd> // IWYU pragma: keep
#include <memory>
#include <type_traits>
#include "art_common.hpp"
#include "assert.hpp"
#include "node_type.hpp"
namespace unodb::detail {
// Forward declarations to use in unodb::db and its siblings
template <class>
class [[nodiscard]] basic_leaf;
template <class, class>
class [[nodiscard]] basic_db_leaf_deleter;
// Internal ART key in binary-comparable format
template <typename KeyType>
struct [[nodiscard]] basic_art_key final {
[[nodiscard, gnu::const]] static UNODB_DETAIL_CONSTEXPR_NOT_MSVC KeyType
make_binary_comparable(KeyType key) noexcept;
constexpr basic_art_key() noexcept = default;
UNODB_DETAIL_CONSTEXPR_NOT_MSVC explicit basic_art_key(KeyType key_) noexcept
: key{make_binary_comparable(key_)} {}
[[nodiscard, gnu::pure]] constexpr bool operator==(
basic_art_key<KeyType> key2) const noexcept {
return !std::memcmp(&key, &key2.key, size);
}
[[nodiscard, gnu::pure]] constexpr auto operator[](
std::size_t index) const noexcept {
UNODB_DETAIL_ASSERT(index < size);
return key_bytes[index];
}
[[nodiscard, gnu::pure]] constexpr explicit operator KeyType()
const noexcept {
return key;
}
constexpr void shift_right(const std::size_t num_bytes) noexcept {
UNODB_DETAIL_ASSERT(num_bytes <= size);
key >>= (num_bytes * 8);
}
static constexpr auto size = sizeof(KeyType);
union {
KeyType key;
std::array<std::byte, size> key_bytes;
};
static void static_asserts() {
static_assert(std::is_trivially_copyable_v<basic_art_key<KeyType>>);
static_assert(sizeof(basic_art_key<KeyType>) == sizeof(KeyType));
}
};
using art_key = basic_art_key<unodb::key>;
[[gnu::cold]] UNODB_DETAIL_NOINLINE void dump_byte(std::ostream &os,
std::byte byte);
[[gnu::cold]] UNODB_DETAIL_NOINLINE std::ostream &operator<<(
std::ostream &os UNODB_DETAIL_LIFETIMEBOUND, art_key key);
class [[nodiscard]] tree_depth final {
public:
using value_type = unsigned;
explicit constexpr tree_depth(value_type value_ = 0) noexcept
: value{value_} {
UNODB_DETAIL_ASSERT(value <= art_key::size);
}
// NOLINTNEXTLINE(google-explicit-constructor)
[[nodiscard, gnu::pure]] constexpr operator value_type() const noexcept {
UNODB_DETAIL_ASSERT(value <= art_key::size);
return value;
}
constexpr tree_depth &operator++() noexcept {
++value;
UNODB_DETAIL_ASSERT(value <= art_key::size);
return *this;
}
constexpr void operator+=(value_type delta) noexcept {
value += delta;
UNODB_DETAIL_ASSERT(value <= art_key::size);
}
private:
value_type value;
};
template <class Header, class Db>
class basic_db_leaf_deleter {
public:
using leaf_type = basic_leaf<Header>;
static_assert(std::is_trivially_destructible_v<leaf_type>);
constexpr explicit basic_db_leaf_deleter(
Db &db_ UNODB_DETAIL_LIFETIMEBOUND) noexcept
: db{db_} {}
void operator()(leaf_type *to_delete) const noexcept;
[[nodiscard, gnu::pure]] Db &get_db() const noexcept { return db; }
private:
Db &db;
};
template <class Header, class Db>
using basic_db_leaf_unique_ptr =
std::unique_ptr<basic_leaf<Header>, basic_db_leaf_deleter<Header, Db>>;
template <class T>
struct dependent_false : std::false_type {};
template <class INode, class Db>
class basic_db_inode_deleter {
public:
constexpr explicit basic_db_inode_deleter(
Db &db_ UNODB_DETAIL_LIFETIMEBOUND) noexcept
: db{db_} {}
void operator()(INode *inode_ptr) noexcept;
[[nodiscard, gnu::pure]] Db &get_db() noexcept { return db; }
private:
Db &db;
};
UNODB_DETAIL_DISABLE_MSVC_WARNING(26490)
template <class Header>
class [[nodiscard]] basic_node_ptr {
public:
using header_type = Header;
// The default constructor does not initialize fields: it is used by
// std::array and we don't want to initialize to zero or any other value there
// at construction time.
// cppcheck-suppress uninitMemberVar
constexpr basic_node_ptr() noexcept = default;
explicit basic_node_ptr(std::nullptr_t) noexcept
: tagged_ptr{reinterpret_cast<std::uintptr_t>(nullptr)} {}
basic_node_ptr(header_type *ptr UNODB_DETAIL_LIFETIMEBOUND,
unodb::node_type type) noexcept
: tagged_ptr{tag_ptr(ptr, type)} {}
basic_node_ptr<Header> &operator=(std::nullptr_t) noexcept {
tagged_ptr = reinterpret_cast<std::uintptr_t>(nullptr);
return *this;
}
[[nodiscard, gnu::pure]] constexpr auto type() const noexcept {
return static_cast<unodb::node_type>(tagged_ptr & tag_bit_mask);
}
[[nodiscard, gnu::pure]] constexpr auto raw_val() const noexcept {
return tagged_ptr;
}
template <class T>
[[nodiscard, gnu::pure]] auto *ptr() const noexcept {
return reinterpret_cast<T>(tagged_ptr & ptr_bit_mask);
}
[[nodiscard, gnu::pure]] auto operator==(std::nullptr_t) const noexcept {
return tagged_ptr == reinterpret_cast<std::uintptr_t>(nullptr);
}
[[nodiscard, gnu::pure]] auto operator!=(std::nullptr_t) const noexcept {
return tagged_ptr != reinterpret_cast<std::uintptr_t>(nullptr);
}
private:
std::uintptr_t tagged_ptr;
[[nodiscard, gnu::const]] static std::uintptr_t tag_ptr(
Header *ptr_, unodb::node_type tag) noexcept {
const auto uintptr = reinterpret_cast<std::uintptr_t>(ptr_);
const auto result =
uintptr | static_cast<std::underlying_type_t<decltype(tag)>>(tag);
UNODB_DETAIL_ASSERT((result & ptr_bit_mask) == uintptr);
return result;
}
[[nodiscard, gnu::const]] static constexpr unsigned mask_bits_needed(
unsigned count) noexcept {
return count < 2 ? 1 : 1 + mask_bits_needed(count >> 1U);
}
static constexpr auto lowest_non_tag_bit =
1ULL << mask_bits_needed(node_type_count);
static constexpr auto tag_bit_mask = lowest_non_tag_bit - 1;
static constexpr auto ptr_bit_mask = ~tag_bit_mask;
static auto static_asserts() {
static_assert(sizeof(basic_node_ptr<Header>) == sizeof(void *));
static_assert(alignof(header_type) - 1 > lowest_non_tag_bit);
}
};
UNODB_DETAIL_RESTORE_MSVC_WARNINGS()
} // namespace unodb::detail
#endif // UNODB_DETAIL_ART_INTERNAL_HPP