]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
11fdf7f2 TL |
2 | // This source code is licensed under both the GPLv2 (found in the |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
7c673cae FG |
5 | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
6 | // Use of this source code is governed by a BSD-style license that can be | |
7 | // found in the LICENSE file. See the AUTHORS file for names of contributors. | |
8 | // | |
9 | // Slice is a simple structure containing a pointer into some external | |
10 | // storage and a size. The user of a Slice must ensure that the slice | |
11 | // is not used after the corresponding external storage has been | |
12 | // deallocated. | |
13 | // | |
14 | // Multiple threads can invoke const methods on a Slice without | |
15 | // external synchronization, but if any of the threads may call a | |
16 | // non-const method, all threads accessing the same Slice must use | |
17 | // external synchronization. | |
18 | ||
11fdf7f2 | 19 | #pragma once |
7c673cae FG |
20 | |
21 | #include <assert.h> | |
7c673cae FG |
22 | #include <stddef.h> |
23 | #include <string.h> | |
494da23a | 24 | #include <cstdio> |
7c673cae FG |
25 | #include <string> |
26 | ||
11fdf7f2 TL |
27 | #ifdef __cpp_lib_string_view |
28 | #include <string_view> | |
29 | #endif | |
30 | ||
7c673cae FG |
31 | #include "rocksdb/cleanable.h" |
32 | ||
f67539c2 | 33 | namespace ROCKSDB_NAMESPACE { |
7c673cae FG |
34 | |
35 | class Slice { | |
36 | public: | |
37 | // Create an empty slice. | |
494da23a | 38 | Slice() : data_(""), size_(0) {} |
7c673cae FG |
39 | |
40 | // Create a slice that refers to d[0,n-1]. | |
494da23a | 41 | Slice(const char* d, size_t n) : data_(d), size_(n) {} |
7c673cae FG |
42 | |
43 | // Create a slice that refers to the contents of "s" | |
44 | /* implicit */ | |
494da23a | 45 | Slice(const std::string& s) : data_(s.data()), size_(s.size()) {} |
7c673cae | 46 | |
11fdf7f2 TL |
47 | #ifdef __cpp_lib_string_view |
48 | // Create a slice that refers to the same contents as "sv" | |
49 | /* implicit */ | |
50 | Slice(std::string_view sv) : data_(sv.data()), size_(sv.size()) {} | |
51 | #endif | |
52 | ||
7c673cae FG |
53 | // Create a slice that refers to s[0,strlen(s)-1] |
54 | /* implicit */ | |
494da23a | 55 | Slice(const char* s) : data_(s) { size_ = (s == nullptr) ? 0 : strlen(s); } |
7c673cae FG |
56 | |
57 | // Create a single slice from SliceParts using buf as storage. | |
58 | // buf must exist as long as the returned Slice exists. | |
59 | Slice(const struct SliceParts& parts, std::string* buf); | |
60 | ||
61 | // Return a pointer to the beginning of the referenced data | |
62 | const char* data() const { return data_; } | |
63 | ||
64 | // Return the length (in bytes) of the referenced data | |
65 | size_t size() const { return size_; } | |
66 | ||
67 | // Return true iff the length of the referenced data is zero | |
68 | bool empty() const { return size_ == 0; } | |
69 | ||
70 | // Return the ith byte in the referenced data. | |
71 | // REQUIRES: n < size() | |
72 | char operator[](size_t n) const { | |
73 | assert(n < size()); | |
74 | return data_[n]; | |
75 | } | |
76 | ||
77 | // Change this slice to refer to an empty array | |
494da23a TL |
78 | void clear() { |
79 | data_ = ""; | |
80 | size_ = 0; | |
81 | } | |
7c673cae FG |
82 | |
83 | // Drop the first "n" bytes from this slice. | |
84 | void remove_prefix(size_t n) { | |
85 | assert(n <= size()); | |
86 | data_ += n; | |
87 | size_ -= n; | |
88 | } | |
89 | ||
90 | void remove_suffix(size_t n) { | |
91 | assert(n <= size()); | |
92 | size_ -= n; | |
93 | } | |
94 | ||
95 | // Return a string that contains the copy of the referenced data. | |
96 | // when hex is true, returns a string of twice the length hex encoded (0-9A-F) | |
97 | std::string ToString(bool hex = false) const; | |
98 | ||
11fdf7f2 TL |
99 | #ifdef __cpp_lib_string_view |
100 | // Return a string_view that references the same data as this slice. | |
101 | std::string_view ToStringView() const { | |
102 | return std::string_view(data_, size_); | |
103 | } | |
104 | #endif | |
105 | ||
7c673cae FG |
106 | // Decodes the current slice interpreted as an hexadecimal string into result, |
107 | // if successful returns true, if this isn't a valid hex string | |
108 | // (e.g not coming from Slice::ToString(true)) DecodeHex returns false. | |
109 | // This slice is expected to have an even number of 0-9A-F characters | |
110 | // also accepts lowercase (a-f) | |
111 | bool DecodeHex(std::string* result) const; | |
112 | ||
113 | // Three-way comparison. Returns value: | |
114 | // < 0 iff "*this" < "b", | |
115 | // == 0 iff "*this" == "b", | |
116 | // > 0 iff "*this" > "b" | |
117 | int compare(const Slice& b) const; | |
118 | ||
119 | // Return true iff "x" is a prefix of "*this" | |
120 | bool starts_with(const Slice& x) const { | |
494da23a | 121 | return ((size_ >= x.size_) && (memcmp(data_, x.data_, x.size_) == 0)); |
7c673cae FG |
122 | } |
123 | ||
124 | bool ends_with(const Slice& x) const { | |
125 | return ((size_ >= x.size_) && | |
126 | (memcmp(data_ + size_ - x.size_, x.data_, x.size_) == 0)); | |
127 | } | |
128 | ||
129 | // Compare two slices and returns the first byte where they differ | |
130 | size_t difference_offset(const Slice& b) const; | |
131 | ||
494da23a | 132 | // private: make these public for rocksdbjni access |
7c673cae FG |
133 | const char* data_; |
134 | size_t size_; | |
135 | ||
136 | // Intentionally copyable | |
137 | }; | |
138 | ||
139 | /** | |
140 | * A Slice that can be pinned with some cleanup tasks, which will be run upon | |
141 | * ::Reset() or object destruction, whichever is invoked first. This can be used | |
11fdf7f2 TL |
142 | * to avoid memcpy by having the PinnableSlice object referring to the data |
143 | * that is locked in the memory and release them after the data is consumed. | |
7c673cae FG |
144 | */ |
145 | class PinnableSlice : public Slice, public Cleanable { | |
146 | public: | |
147 | PinnableSlice() { buf_ = &self_space_; } | |
148 | explicit PinnableSlice(std::string* buf) { buf_ = buf; } | |
149 | ||
f67539c2 TL |
150 | PinnableSlice(PinnableSlice&& other); |
151 | PinnableSlice& operator=(PinnableSlice&& other); | |
152 | ||
11fdf7f2 TL |
153 | // No copy constructor and copy assignment allowed. |
154 | PinnableSlice(PinnableSlice&) = delete; | |
155 | PinnableSlice& operator=(PinnableSlice&) = delete; | |
156 | ||
7c673cae FG |
157 | inline void PinSlice(const Slice& s, CleanupFunction f, void* arg1, |
158 | void* arg2) { | |
159 | assert(!pinned_); | |
160 | pinned_ = true; | |
161 | data_ = s.data(); | |
162 | size_ = s.size(); | |
163 | RegisterCleanup(f, arg1, arg2); | |
164 | assert(pinned_); | |
165 | } | |
166 | ||
167 | inline void PinSlice(const Slice& s, Cleanable* cleanable) { | |
168 | assert(!pinned_); | |
169 | pinned_ = true; | |
170 | data_ = s.data(); | |
171 | size_ = s.size(); | |
172 | cleanable->DelegateCleanupsTo(this); | |
173 | assert(pinned_); | |
174 | } | |
175 | ||
176 | inline void PinSelf(const Slice& slice) { | |
177 | assert(!pinned_); | |
178 | buf_->assign(slice.data(), slice.size()); | |
179 | data_ = buf_->data(); | |
180 | size_ = buf_->size(); | |
181 | assert(!pinned_); | |
182 | } | |
183 | ||
184 | inline void PinSelf() { | |
185 | assert(!pinned_); | |
186 | data_ = buf_->data(); | |
187 | size_ = buf_->size(); | |
188 | assert(!pinned_); | |
189 | } | |
190 | ||
191 | void remove_suffix(size_t n) { | |
192 | assert(n <= size()); | |
193 | if (pinned_) { | |
194 | size_ -= n; | |
195 | } else { | |
196 | buf_->erase(size() - n, n); | |
197 | PinSelf(); | |
198 | } | |
199 | } | |
200 | ||
f67539c2 TL |
201 | void remove_prefix(size_t n) { |
202 | assert(n <= size()); | |
203 | if (pinned_) { | |
204 | data_ += n; | |
205 | size_ -= n; | |
206 | } else { | |
207 | buf_->erase(0, n); | |
208 | PinSelf(); | |
209 | } | |
7c673cae FG |
210 | } |
211 | ||
212 | void Reset() { | |
213 | Cleanable::Reset(); | |
214 | pinned_ = false; | |
494da23a | 215 | size_ = 0; |
7c673cae FG |
216 | } |
217 | ||
218 | inline std::string* GetSelf() { return buf_; } | |
219 | ||
f67539c2 | 220 | inline bool IsPinned() const { return pinned_; } |
7c673cae FG |
221 | |
222 | private: | |
223 | friend class PinnableSlice4Test; | |
224 | std::string self_space_; | |
225 | std::string* buf_; | |
226 | bool pinned_ = false; | |
227 | }; | |
228 | ||
229 | // A set of Slices that are virtually concatenated together. 'parts' points | |
230 | // to an array of Slices. The number of elements in the array is 'num_parts'. | |
231 | struct SliceParts { | |
494da23a TL |
232 | SliceParts(const Slice* _parts, int _num_parts) |
233 | : parts(_parts), num_parts(_num_parts) {} | |
7c673cae FG |
234 | SliceParts() : parts(nullptr), num_parts(0) {} |
235 | ||
236 | const Slice* parts; | |
237 | int num_parts; | |
238 | }; | |
239 | ||
240 | inline bool operator==(const Slice& x, const Slice& y) { | |
241 | return ((x.size() == y.size()) && | |
242 | (memcmp(x.data(), y.data(), x.size()) == 0)); | |
243 | } | |
244 | ||
494da23a | 245 | inline bool operator!=(const Slice& x, const Slice& y) { return !(x == y); } |
7c673cae FG |
246 | |
247 | inline int Slice::compare(const Slice& b) const { | |
11fdf7f2 | 248 | assert(data_ != nullptr && b.data_ != nullptr); |
7c673cae FG |
249 | const size_t min_len = (size_ < b.size_) ? size_ : b.size_; |
250 | int r = memcmp(data_, b.data_, min_len); | |
251 | if (r == 0) { | |
494da23a TL |
252 | if (size_ < b.size_) |
253 | r = -1; | |
254 | else if (size_ > b.size_) | |
255 | r = +1; | |
7c673cae FG |
256 | } |
257 | return r; | |
258 | } | |
259 | ||
260 | inline size_t Slice::difference_offset(const Slice& b) const { | |
261 | size_t off = 0; | |
262 | const size_t len = (size_ < b.size_) ? size_ : b.size_; | |
263 | for (; off < len; off++) { | |
264 | if (data_[off] != b.data_[off]) break; | |
265 | } | |
266 | return off; | |
267 | } | |
268 | ||
f67539c2 | 269 | } // namespace ROCKSDB_NAMESPACE |