YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/faststring.h
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
#ifndef YB_UTIL_FASTSTRING_H_
33
#define YB_UTIL_FASTSTRING_H_
34
35
#include <string>
36
37
#include "yb/gutil/dynamic_annotations.h"
38
#include "yb/gutil/macros.h"
39
#include "yb/gutil/strings/fastmem.h"
40
41
namespace yb {
42
43
// A faststring is similar to a std::string, except that it is faster for many
44
// common use cases (in particular, resize() will fill with uninitialized data
45
// instead of memsetting to \0)
46
class faststring {
47
 public:
48
  // Tell PVS Studio it is OK that initial_data_ is uninitialized.
49
  //-V:initial_data_:730
50
  faststring()
51
      : data_(initial_data_),
52
        len_(0),
53
31.9M
        capacity_(kInitialCapacity) {
54
31.9M
  }
55
56
  // Construct a string with the given capacity, in bytes.
57
  // Tell PVS Studio it is OK that initial_data_ is uninitialized.
58
  //-V:initial_data_:730
59
  explicit faststring(size_t capacity)
60
      : data_(initial_data_),
61
        len_(0),
62
0
        capacity_(kInitialCapacity) {
63
0
    if (capacity > capacity_) {
64
0
      data_ = new uint8_t[capacity];
65
0
      capacity_ = capacity;
66
0
    }
67
0
    ASAN_POISON_MEMORY_REGION(data_, capacity_);
68
0
  }
69
70
31.9M
  ~faststring() {
71
31.9M
    ASAN_UNPOISON_MEMORY_REGION(initial_data_, arraysize(initial_data_));
72
31.9M
    if (data_ != initial_data_) {
73
19.0M
      delete[] data_;
74
19.0M
    }
75
31.9M
  }
76
77
  // Reset the valid length of the string to 0.
78
  //
79
  // This does not free up any memory. The capacity of the string remains unchanged.
80
16.7M
  void clear() {
81
16.7M
    resize(0);
82
16.7M
    ASAN_POISON_MEMORY_REGION(data_, capacity_);
83
16.7M
  }
84
85
  // Resize the string to the given length.
86
  // If the new length is larger than the old length, the capacity is expanded as necessary.
87
  //
88
  // NOTE: in contrast to std::string's implementation, Any newly "exposed" bytes of data are
89
  // not cleared.
90
36.8M
  void resize(size_t newsize) {
91
36.8M
    if (newsize > capacity_) {
92
2.62M
      reserve(newsize);
93
2.62M
    }
94
36.8M
    len_ = newsize;
95
36.8M
    ASAN_POISON_MEMORY_REGION(data_ + len_, capacity_ - len_);
96
36.8M
    ASAN_UNPOISON_MEMORY_REGION(data_, len_);
97
36.8M
  }
98
99
  // Releases the underlying array; after this, the buffer is left empty.
100
  //
101
  // NOTE: the data pointer returned by release() is not necessarily the pointer
102
0
  uint8_t *release() WARN_UNUSED_RESULT {
103
0
    uint8_t *ret = data_;
104
0
    if (ret == initial_data_) {
105
0
      ret = new uint8_t[len_];
106
0
      memcpy(ret, data_, len_);
107
0
    }
108
0
    len_ = 0;
109
0
    capacity_ = kInitialCapacity;
110
0
    data_ = initial_data_;
111
0
    ASAN_POISON_MEMORY_REGION(data_, capacity_);
112
0
    return ret;
113
0
  }
114
115
  // Reserve space for the given total amount of data. If the current capacity is already
116
  // larger than the newly requested capacity, this is a no-op (i.e. it does not ever free memory).
117
  //
118
  // NOTE: even though the new capacity is reserved, it is illegal to begin writing into that memory
119
  // directly using pointers. If ASAN is enabled, this is ensured using manual memory poisoning.
120
16.5M
  void reserve(size_t newcapacity) {
121
16.5M
    if (PREDICT_TRUE(newcapacity <= capacity_)) return;
122
10.3M
    GrowArray(newcapacity);
123
10.3M
  }
124
125
  // Append the given data to the string, resizing capacity as necessary.
126
572M
  void append(const void *src_v, size_t count) {
127
572M
    const uint8_t *src = reinterpret_cast<const uint8_t *>(src_v);
128
572M
    EnsureRoomForAppend(count);
129
572M
    ASAN_UNPOISON_MEMORY_REGION(data_ + len_, count);
130
131
    // appending short values is common enough that this
132
    // actually helps, according to benchmarks. In theory
133
    // memcpy_inlined should already be just as good, but this
134
    // was ~20% faster for reading a large prefix-coded string file
135
    // where each string was only a few chars different
136
572M
    if (count <= 4) {
137
470M
      uint8_t *p = &data_[len_];
138
1.45G
      for (size_t i = 0; i < count; i++) {
139
987M
        *p++ = *src++;
140
987M
      }
141
102M
    } else {
142
102M
      strings::memcpy_inlined(&data_[len_], src, count);
143
102M
    }
144
572M
    len_ += count;
145
572M
  }
146
147
  // Append the given string to this string.
148
47.5M
  void append(const std::string &str) {
149
47.5M
    append(str.data(), str.size());
150
47.5M
  }
151
152
  // Append the given character to this string.
153
0
  void push_back(const char byte) {
154
0
    EnsureRoomForAppend(1);
155
0
    ASAN_UNPOISON_MEMORY_REGION(data_ + len_, 1);
156
0
    data_[len_] = byte;
157
0
    len_++;
158
0
  }
Unexecuted instantiation: _ZN2yb10faststring9push_backEc
Unexecuted instantiation: _ZN2yb10faststring9push_backEc
159
160
  // Return true if the string is empty.
161
8.28M
  bool empty() const {
162
8.28M
    return len_ == 0;
163
8.28M
  }
164
165
  // Return the valid length of this string.
166
25.7k
  size_t length() const {
167
25.7k
    return len_;
168
25.7k
  }
169
170
  // Return the valid length of this string (identical to length())
171
59.9M
  size_t size() const {
172
59.9M
    return len_;
173
59.9M
  }
174
175
  // Return the allocated capacity of this string.
176
0
  size_t capacity() const {
177
0
    return capacity_;
178
0
  }
179
180
  // Return a pointer to the data in this string. Note that this pointer
181
  // may be invalidated by any later non-const operation.
182
28.8M
  const uint8_t *data() const {
183
28.8M
    return &data_[0];
184
28.8M
  }
185
186
  // Return a pointer to the data in this string. Note that this pointer
187
  // may be invalidated by any later non-const operation.
188
64
  const char *c_str() const {
189
64
    return reinterpret_cast<const char *>(data());
190
64
  }
191
192
  // Return a pointer to the data in this string. Note that this pointer
193
  // may be invalidated by any later non-const operation.
194
72.3M
  uint8_t *data() {
195
72.3M
    return &data_[0];
196
72.3M
  }
197
198
  // Return the given element of this string. Note that this does not perform
199
  // any bounds checking.
200
0
  const uint8_t &at(size_t i) const {
201
0
    return data_[i];
202
0
  }
203
204
  // Return the given element of this string. Note that this does not perform
205
  // any bounds checking.
206
0
  const uint8_t &operator[](size_t i) const {
207
0
    return data_[i];
208
0
  }
209
210
  // Return the given element of this string. Note that this does not perform
211
  // any bounds checking.
212
22.4M
  uint8_t &operator[](size_t i) {
213
22.4M
    return data_[i];
214
22.4M
  }
215
216
  // Reset the contents of this string by copying 'len' bytes from 'src'.
217
0
  void assign_copy(const uint8_t *src, size_t len) {
218
0
    // Reset length so that the first resize doesn't need to copy the current
219
0
    // contents of the array.
220
0
    len_ = 0;
221
0
    resize(len);
222
0
    memcpy(data(), src, len);
223
0
  }
224
225
  // Reset the contents of this string by copying from the given std::string.
226
0
  void assign_copy(const std::string &str) {
227
0
    assign_copy(reinterpret_cast<const uint8_t *>(str.c_str()),
228
0
                str.size());
229
0
  }
230
231
0
  void CopyFrom(const faststring& other) {
232
0
    clear();
233
0
    append(other.data(), other.size());
234
0
  }
235
236
  // Return a copy of this string as a std::string.
237
507
  std::string ToString() const {
238
507
    return std::string(reinterpret_cast<const char *>(data()),
239
507
                       len_);
240
507
  }
241
242
 private:
243
244
  // If necessary, expand the buffer to fit at least 'count' more bytes.
245
  // If the array has to be grown, it is grown by at least 50%.
246
572M
  void EnsureRoomForAppend(size_t count) {
247
572M
    if (PREDICT_TRUE(len_ + count <= capacity_)) {
248
553M
      return;
249
553M
    }
250
251
    // Call the non-inline slow path - this reduces the number of instructions
252
    // on the hot path.
253
18.9M
    GrowByAtLeast(count);
254
18.9M
  }
255
256
  // The slow path of MakeRoomFor. Grows the buffer by either
257
  // 'count' bytes, or 50%, whichever is more.
258
  void GrowByAtLeast(size_t count);
259
260
  // Grow the array to the given capacity, which must be more than
261
  // the current capacity.
262
  void GrowArray(size_t newcapacity);
263
264
  enum {
265
    kInitialCapacity = 32
266
  };
267
268
  uint8_t* data_;
269
  uint8_t initial_data_[kInitialCapacity];
270
  size_t len_;
271
  size_t capacity_;
272
273
  DISALLOW_COPY_AND_ASSIGN(faststring);
274
};
275
276
}  // namespace yb
277
278
#endif  // YB_UTIL_FASTSTRING_H_