1 // Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
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).
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 
19 #pragma once
20 
21 #include <assert.h>
22 #include <stddef.h>
23 #include <string.h>
24 #include <cstdio>
25 #include <string>
26 
27 #ifdef __cpp_lib_string_view
28 #include <string_view>
29 #endif
30 
31 #include "rocksdb/cleanable.h"
32 
33 namespace ROCKSDB_NAMESPACE {
34 
35 class Slice {
36  public:
37   // Create an empty slice.
Slice()38   Slice() : data_(""), size_(0) {}
39 
40   // Create a slice that refers to d[0,n-1].
Slice(const char * d,size_t n)41   Slice(const char* d, size_t n) : data_(d), size_(n) {}
42 
43   // Create a slice that refers to the contents of "s"
44   /* implicit */
Slice(const std::string & s)45   Slice(const std::string& s) : data_(s.data()), size_(s.size()) {}
46 
47 #ifdef __cpp_lib_string_view
48   // Create a slice that refers to the same contents as "sv"
49   /* implicit */
Slice(std::string_view sv)50   Slice(std::string_view sv) : data_(sv.data()), size_(sv.size()) {}
51 #endif
52 
53   // Create a slice that refers to s[0,strlen(s)-1]
54   /* implicit */
Slice(const char * s)55   Slice(const char* s) : data_(s) { size_ = (s == nullptr) ? 0 : strlen(s); }
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
data()62   const char* data() const { return data_; }
63 
64   // Return the length (in bytes) of the referenced data
size()65   size_t size() const { return size_; }
66 
67   // Return true iff the length of the referenced data is zero
empty()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
clear()78   void clear() {
79     data_ = "";
80     size_ = 0;
81   }
82 
83   // Drop the first "n" bytes from this slice.
remove_prefix(size_t n)84   void remove_prefix(size_t n) {
85     assert(n <= size());
86     data_ += n;
87     size_ -= n;
88   }
89 
remove_suffix(size_t n)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 
99 #ifdef __cpp_lib_string_view
100   // Return a string_view that references the same data as this slice.
ToStringView()101   std::string_view ToStringView() const {
102     return std::string_view(data_, size_);
103   }
104 #endif
105 
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"
starts_with(const Slice & x)120   bool starts_with(const Slice& x) const {
121     return ((size_ >= x.size_) && (memcmp(data_, x.data_, x.size_) == 0));
122   }
123 
ends_with(const Slice & x)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 
132   // private: make these public for rocksdbjni access
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
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.
144  */
145 class PinnableSlice : public Slice, public Cleanable {
146  public:
PinnableSlice()147   PinnableSlice() { buf_ = &self_space_; }
PinnableSlice(std::string * buf)148   explicit PinnableSlice(std::string* buf) { buf_ = buf; }
149 
150   PinnableSlice(PinnableSlice&& other);
151   PinnableSlice& operator=(PinnableSlice&& other);
152 
153   // No copy constructor and copy assignment allowed.
154   PinnableSlice(PinnableSlice&) = delete;
155   PinnableSlice& operator=(PinnableSlice&) = delete;
156 
PinSlice(const Slice & s,CleanupFunction f,void * arg1,void * arg2)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 
PinSlice(const Slice & s,Cleanable * cleanable)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 
PinSelf(const Slice & slice)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 
PinSelf()184   inline void PinSelf() {
185     assert(!pinned_);
186     data_ = buf_->data();
187     size_ = buf_->size();
188     assert(!pinned_);
189   }
190 
remove_suffix(size_t n)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 
remove_prefix(size_t n)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     }
210   }
211 
Reset()212   void Reset() {
213     Cleanable::Reset();
214     pinned_ = false;
215     size_ = 0;
216   }
217 
GetSelf()218   inline std::string* GetSelf() { return buf_; }
219 
IsPinned()220   inline bool IsPinned() const { return pinned_; }
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 {
SlicePartsSliceParts232   SliceParts(const Slice* _parts, int _num_parts)
233       : parts(_parts), num_parts(_num_parts) {}
SlicePartsSliceParts234   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 
245 inline bool operator!=(const Slice& x, const Slice& y) { return !(x == y); }
246 
compare(const Slice & b)247 inline int Slice::compare(const Slice& b) const {
248   assert(data_ != nullptr && b.data_ != nullptr);
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) {
252     if (size_ < b.size_)
253       r = -1;
254     else if (size_ > b.size_)
255       r = +1;
256   }
257   return r;
258 }
259 
difference_offset(const Slice & b)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 
269 }  // namespace ROCKSDB_NAMESPACE
270