-
Notifications
You must be signed in to change notification settings - Fork 0
/
masstree_key.hh
240 lines (224 loc) · 7.51 KB
/
masstree_key.hh
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
232
233
234
235
236
237
238
239
240
/* Masstree
* Eddie Kohler, Yandong Mao, Robert Morris
* Copyright (c) 2012-2014 President and Fellows of Harvard College
* Copyright (c) 2012-2014 Massachusetts Institute of Technology
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, subject to the conditions
* listed in the Masstree LICENSE file. These conditions include: you must
* preserve this copyright notice, and you cannot mention the copyright
* holders in advertising related to the Software without their permission.
* The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
* notice is a summary of the Masstree LICENSE file; the license in that file
* is legally binding.
*/
#ifndef MASSTREE_KEY_HH
#define MASSTREE_KEY_HH
#include "masstree.hh"
#include "string_slice.hh"
namespace Masstree {
/** @brief Strings used as Masstree keys.
Masstree key strings are divided into parts: an initial slice, called
the <em>ikey</em>, and a suffix. The ikey is stored as a byte-swapped
integer, which is faster to compare than a string.
Keys can be <em>shifted</em> by the shift() method. <code>k.shift()</code>
is like <code>k = key(k.suffix())</code>: the key is reconstructed from
the original key's suffix. This corresponds to descending a layer in
Masstree. However, <code>k.shift()</code> is faster than the assignment,
and its effects can be undone by the <code>k.unshift_all()</code>
method. */
template <typename I>
class key {
public:
static constexpr int nikey = 1;
/** @brief Type of ikeys. */
typedef I ikey_type;
/** @brief Size of ikeys in bytes. */
static constexpr int ikey_size = sizeof(ikey_type);
/** @brief Construct an uninitialized key. */
key() {
}
/** @brief Construct a key for string @a s. */
key(Str s)
: ikey0_(string_slice<ikey_type>::make_comparable(s.s, s.len)),
len_(s.len), s_(s.s), first_(s.s) {
}
/** @brief Construct a key for string @a s with length @a len.
@pre @a len >= 0 */
key(const char* s, int len)
: ikey0_(string_slice<ikey_type>::make_comparable(s, len)),
len_(len), s_(s), first_(s) {
}
/** @brief Construct a key for ikey @a ikey.
Any trailing zero bytes in @a ikey are not counted towards the key's
length. */
explicit key(ikey_type ikey)
: ikey0_(ikey),
len_(ikey ? ikey_size - ctz(ikey) / 8 : 0), s_(0), first_(0) {
}
/** @brief Construct a key for ikey @a ikey with length @a len.
@pre @a len >= 0
@post length() >= 0 && length() <= ikey_size */
key(ikey_type ikey, int len)
: ikey0_(ikey),
len_(std::min(len, ikey_size)), s_(0), first_(0) {
}
/** @brief Construct a key with ikey @a ikey and suffix @a suf. */
key(ikey_type ikey, Str suf)
: ikey0_(ikey),
len_(ikey_size + suf.len), s_(suf.s - ikey_size), first_(s_) {
}
/** @brief Test if this key is empty (holds the empty string). */
bool empty() const {
return ikey0_ == 0 && len_ == 0;
}
/** @brief Return the ikey. */
ikey_type ikey() const {
return ikey0_;
}
/** @brief Return the key's length. */
int length() const {
return len_;
}
/** @brief Test whether this key has a suffix (length() > ikey_size). */
bool has_suffix() const {
return len_ > ikey_size;
}
/** @brief Return this key's suffix.
@pre has_suffix() */
Str suffix() const {
return Str(s_ + ikey_size, len_ - ikey_size);
}
/** @brief Return the length of this key's suffix.
@pre has_suffix() */
int suffix_length() const {
return len_ - ikey_size;
}
/** @brief Shift this key forward to model the current key's suffix.
@pre has_suffix() */
void shift() {
s_ += ikey_size;
len_ -= ikey_size;
ikey0_ = string_slice<ikey_type>::make_comparable_sloppy(s_, len_);
}
/** @brief Shift this key forward to model the current key's suffix.
@pre has_suffix() */
void shift_by(int delta) {
s_ += delta;
len_ -= delta;
ikey0_ = string_slice<ikey_type>::make_comparable_sloppy(s_, len_);
}
/** @brief Test whether this key has been shifted by shift(). */
bool is_shifted() const {
return first_ != s_;
}
/** @brief Undo all previous shift() calls. */
void unshift_all() {
if (s_ != first_) {
len_ += s_ - first_;
s_ = first_;
ikey0_ = string_slice<ikey_type>::make_comparable(s_, len_);
}
}
int compare(ikey_type ikey, int keylenx) const {
int cmp = ::compare(this->ikey(), ikey);
if (cmp == 0) {
int al = this->length();
if (al > ikey_size)
cmp = keylenx <= ikey_size;
else
cmp = al - keylenx;
}
return cmp;
}
int compare(const key<I>& x) const {
return compare(x.ikey(), x.length());
}
int unparse(char* data, int datalen) const {
int cplen = std::min(len_, datalen);
string_slice<ikey_type>::unparse_comparable(data, cplen, ikey0_, ikey_size);
if (cplen > ikey_size)
memcpy(data + ikey_size, s_ + ikey_size, cplen - ikey_size);
return cplen;
}
String unparse() const {
String s = String::make_uninitialized(len_);
unparse(s.mutable_data(), s.length());
return s;
}
int unparse_printable(char* data, int datalen) const {
String s = unparse().printable();
int cplen = std::min(s.length(), datalen);
memcpy(data, s.data(), cplen);
return cplen;
}
static String unparse_ikey(ikey_type ikey) {
key<ikey_type> k(ikey);
return k.unparse();
}
// used during scan
Str prefix_string() const {
return Str(first_, s_);
}
int prefix_length() const {
return s_ - first_;
}
Str full_string() const {
return Str(first_, s_ + len_);
}
operator Str() const {
return full_string();
}
bool increment() {
// Return true iff wrapped.
if (has_suffix()) {
++ikey0_;
len_ = 1;
return unlikely(!ikey0_);
} else {
++len_;
return false;
}
}
void assign_store_ikey(ikey_type ikey) {
ikey0_ = ikey;
*reinterpret_cast<ikey_type*>(const_cast<char*>(s_)) = host_to_net_order(ikey);
}
int assign_store_suffix(Str s) {
memcpy(const_cast<char*>(s_ + ikey_size), s.s, s.len);
return ikey_size + s.len;
}
void assign_store_length(int len) {
len_ = len;
}
void unshift() {
masstree_precondition(is_shifted());
s_ -= ikey_size;
ikey0_ = string_slice<ikey_type>::make_comparable_sloppy(s_, ikey_size);
len_ = ikey_size + 1;
}
void shift_clear() {
ikey0_ = 0;
len_ = 0;
s_ += ikey_size;
}
void shift_clear_reverse() {
ikey0_ = ~ikey_type(0);
len_ = ikey_size + 1;
s_ += ikey_size;
}
private:
ikey_type ikey0_;
int len_;
const char* s_;
const char* first_;
};
template <typename I> constexpr int key<I>::ikey_size;
} // namespace Masstree
template <typename I>
inline std::ostream& operator<<(std::ostream& stream,
const Masstree::key<I>& x) {
return stream << x.unparse();
}
#endif