2 * Eddie Kohler, Yandong Mao, Robert Morris
3 * Copyright (c) 2012-2014 President and Fellows of Harvard College
4 * Copyright (c) 2012-2014 Massachusetts Institute of Technology
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, subject to the conditions
9 * listed in the Masstree LICENSE file. These conditions include: you must
10 * preserve this copyright notice, and you cannot mention the copyright
11 * holders in advertising related to the Software without their permission.
12 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
13 * notice is a summary of the Masstree LICENSE file; the license in that file
16 #ifndef MASSTREE_KEY_HH
17 #define MASSTREE_KEY_HH
18 #include "masstree.hh"
19 #include "string_slice.hh"
23 /** @brief Strings used as Masstree keys.
25 Masstree key strings are divided into parts: an initial slice, called
26 the <em>ikey</em>, and a suffix. The ikey is stored as a byte-swapped
27 integer, which is faster to compare than a string.
29 Keys can be <em>shifted</em> by the shift() method. <code>k.shift()</code>
30 is like <code>k = key(k.suffix())</code>: the key is reconstructed from
31 the original key's suffix. This corresponds to descending a layer in
32 Masstree. However, <code>k.shift()</code> is faster than the assignment,
33 and its effects can be undone by the <code>k.unshift_all()</code>
38 static constexpr int nikey = 1;
39 /** @brief Type of ikeys. */
41 /** @brief Size of ikeys in bytes. */
42 static constexpr int ikey_size = sizeof(ikey_type);
44 /** @brief Construct an uninitialized key. */
47 /** @brief Construct a key for string @a s. */
49 : ikey0_(string_slice<ikey_type>::make_comparable(s.s, s.len)),
50 len_(s.len), s_(s.s), first_(s.s) {
52 /** @brief Construct a key for string @a s with length @a len.
54 key(const char* s, int len)
55 : ikey0_(string_slice<ikey_type>::make_comparable(s, len)),
56 len_(len), s_(s), first_(s) {
58 /** @brief Construct a key for ikey @a ikey.
60 Any trailing zero bytes in @a ikey are not counted towards the key's
62 explicit key(ikey_type ikey)
64 len_(ikey ? ikey_size - ctz(ikey) / 8 : 0), s_(0), first_(0) {
66 /** @brief Construct a key for ikey @a ikey with length @a len.
68 @post length() >= 0 && length() <= ikey_size */
69 key(ikey_type ikey, int len)
71 len_(std::min(len, ikey_size)), s_(0), first_(0) {
73 /** @brief Construct a key with ikey @a ikey and suffix @a suf. */
74 key(ikey_type ikey, Str suf)
76 len_(ikey_size + suf.len), s_(suf.s - ikey_size), first_(s_) {
79 /** @brief Test if this key is empty (holds the empty string). */
81 return ikey0_ == 0 && len_ == 0;
83 /** @brief Return the ikey. */
84 ikey_type ikey() const {
87 /** @brief Return the key's length. */
91 /** @brief Test whether this key has a suffix (length() > ikey_size). */
92 bool has_suffix() const {
93 return len_ > ikey_size;
95 /** @brief Return this key's suffix.
98 return Str(s_ + ikey_size, len_ - ikey_size);
100 /** @brief Return the length of this key's suffix.
102 int suffix_length() const {
103 return len_ - ikey_size;
106 /** @brief Shift this key forward to model the current key's suffix.
111 ikey0_ = string_slice<ikey_type>::make_comparable_sloppy(s_, len_);
113 /** @brief Shift this key forward to model the current key's suffix.
115 void shift_by(int delta) {
118 ikey0_ = string_slice<ikey_type>::make_comparable_sloppy(s_, len_);
120 /** @brief Test whether this key has been shifted by shift(). */
121 bool is_shifted() const {
124 /** @brief Undo all previous shift() calls. */
129 ikey0_ = string_slice<ikey_type>::make_comparable(s_, len_);
133 int compare(ikey_type ikey, int keylenx) const {
134 int cmp = ::compare(this->ikey(), ikey);
136 int al = this->length();
138 cmp = keylenx <= ikey_size;
144 int compare(const key<I>& x) const {
145 return compare(x.ikey(), x.length());
148 int unparse(char* data, int datalen) const {
149 int cplen = std::min(len_, datalen);
150 string_slice<ikey_type>::unparse_comparable(data, cplen, ikey0_, ikey_size);
151 if (cplen > ikey_size)
152 memcpy(data + ikey_size, s_ + ikey_size, cplen - ikey_size);
155 String unparse() const {
156 String s = String::make_uninitialized(len_);
157 unparse(s.mutable_data(), s.length());
160 int unparse_printable(char* data, int datalen) const {
161 String s = unparse().printable();
162 int cplen = std::min(s.length(), datalen);
163 memcpy(data, s.data(), cplen);
166 static String unparse_ikey(ikey_type ikey) {
167 key<ikey_type> k(ikey);
172 Str prefix_string() const {
173 return Str(first_, s_);
175 int prefix_length() const {
178 Str full_string() const {
179 return Str(first_, s_ + len_);
181 operator Str() const {
182 return full_string();
185 // Return true iff wrapped.
189 return unlikely(!ikey0_);
195 void assign_store_ikey(ikey_type ikey) {
197 *reinterpret_cast<ikey_type*>(const_cast<char*>(s_)) = host_to_net_order(ikey);
199 int assign_store_suffix(Str s) {
200 memcpy(const_cast<char*>(s_ + ikey_size), s.s, s.len);
201 return ikey_size + s.len;
203 void assign_store_length(int len) {
207 masstree_precondition(is_shifted());
209 ikey0_ = string_slice<ikey_type>::make_comparable_sloppy(s_, ikey_size);
210 len_ = ikey_size + 1;
217 void shift_clear_reverse() {
218 ikey0_ = ~ikey_type(0);
219 len_ = ikey_size + 1;
230 template <typename I> constexpr int key<I>::ikey_size;
232 } // namespace Masstree
234 template <typename I>
235 inline std::ostream& operator<<(std::ostream& stream,
236 const Masstree::key<I>& x) {
237 return stream << x.unparse();