YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/memcmpable_varint.cc
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
// This file contains code derived from sqlite4, distributed in the public domain.
33
//
34
// A variable length integer is an encoding of 64-bit unsigned integers
35
// into between 1 and 9 bytes.  The encoding is designed so that small
36
// (and common) values take much less space that larger values.  Additional
37
// properties:
38
//
39
//    *  The length of the varint can be determined after examining just
40
//       the first byte of the encoding.
41
//
42
//    *  Varints compare in numerical order using memcmp().
43
//
44
//************************************************************************
45
//
46
// Treat each byte of the encoding as an unsigned integer between 0 and 255.
47
// Let the bytes of the encoding be called A0, A1, A2, ..., A8.
48
//
49
// DECODE
50
//
51
// If A0 is between 0 and 240 inclusive, then the result is the value of A0.
52
//
53
// If A0 is between 241 and 248 inclusive, then the result is
54
// 240+256*(A0-241)+A1.
55
//
56
// If A0 is 249 then the result is 2288+256*A1+A2.
57
//
58
// If A0 is 250 then the result is A1..A3 as a 3-byte big-ending integer.
59
//
60
// If A0 is 251 then the result is A1..A4 as a 4-byte big-ending integer.
61
//
62
// If A0 is 252 then the result is A1..A5 as a 5-byte big-ending integer.
63
//
64
// If A0 is 253 then the result is A1..A6 as a 6-byte big-ending integer.
65
//
66
// If A0 is 254 then the result is A1..A7 as a 7-byte big-ending integer.
67
//
68
// If A0 is 255 then the result is A1..A8 as a 8-byte big-ending integer.
69
//
70
// ENCODE
71
//
72
// Let the input value be V.
73
//
74
// If V<=240 then output a single by A0 equal to V.
75
//
76
// If V<=2287 then output A0 as (V-240)/256 + 241 and A1 as (V-240)%256.
77
//
78
// If V<=67823 then output A0 as 249, A1 as (V-2288)/256, and A2
79
// as (V-2288)%256.
80
//
81
// If V<=16777215 then output A0 as 250 and A1 through A3 as a big-endian
82
// 3-byte integer.
83
//
84
// If V<=4294967295 then output A0 as 251 and A1..A4 as a big-ending
85
// 4-byte integer.
86
//
87
// If V<=1099511627775 then output A0 as 252 and A1..A5 as a big-ending
88
// 5-byte integer.
89
//
90
// If V<=281474976710655 then output A0 as 253 and A1..A6 as a big-ending
91
// 6-byte integer.
92
//
93
// If V<=72057594037927935 then output A0 as 254 and A1..A7 as a
94
// big-ending 7-byte integer.
95
//
96
// Otherwise then output A0 as 255 and A1..A8 as a big-ending 8-byte integer.
97
//
98
// SUMMARY
99
//
100
//    Bytes    Max Value    Digits
101
//    -------  ---------    ---------
102
//      1      240           2.3
103
//      2      2287          3.3
104
//      3      67823         4.8
105
//      4      2**24-1       7.2
106
//      5      2**32-1       9.6
107
//      6      2**40-1      12.0
108
//      7      2**48-1      14.4
109
//      8      2**56-1      16.8
110
//      9      2**64-1      19.2
111
//
112
#include "yb/util/memcmpable_varint.h"
113
114
#include <glog/logging.h>
115
116
#include "yb/util/cast.h"
117
#include "yb/util/faststring.h"
118
#include "yb/util/slice.h"
119
#include "yb/util/status.h"
120
121
namespace yb {
122
123
////////////////////////////////////////////////////////////
124
// Begin code ripped from sqlite4
125
////////////////////////////////////////////////////////////
126
127
// This function is borrowed from sqlite4/varint.c
128
221k
static void varintWrite32(uint8_t *z, uint32_t y) {
129
221k
  z[0] = (uint8_t)(y>>24);
130
221k
  z[1] = (uint8_t)(y>>16);
131
221k
  z[2] = (uint8_t)(y>>8);
132
221k
  z[3] = (uint8_t)(y);
133
221k
}
134
135
136
// Write a varint into z[].  The buffer z[] must be at least 9 characters
137
// long to accommodate the largest possible varint.  Return the number of
138
// bytes of z[] used.
139
//
140
// This function is borrowed from sqlite4/varint.c
141
305k
static size_t sqlite4PutVarint64(uint8_t *z, uint64_t x) {
142
305k
  if (x <= 240) {
143
21.2k
    z[0] = (uint8_t)x;
144
21.2k
    return 1;
145
21.2k
  }
146
284k
  if (x <= 2287) {
147
22.5k
    auto y = x - 240;
148
22.5k
    z[0] = (uint8_t)(y/256 + 241);
149
22.5k
    z[1] = (uint8_t)(y%256);
150
22.5k
    return 2;
151
22.5k
  }
152
261k
  if (x <= 67823) {
153
86.1k
    auto y = x - 2288;
154
86.1k
    z[0] = 249;
155
86.1k
    z[1] = (uint8_t)(y/256);
156
86.1k
    z[2] = (uint8_t)(y%256);
157
86.1k
    return 3;
158
86.1k
  }
159
175k
  auto y = static_cast<uint32_t>(x);
160
175k
  auto w = static_cast<uint32_t>(x >> 32);
161
175k
  if (w == 0) {
162
73.8k
    if (y <= 16777215) {
163
52.9k
      z[0] = 250;
164
52.9k
      z[1] = (uint8_t)(y>>16);
165
52.9k
      z[2] = (uint8_t)(y>>8);
166
52.9k
      z[3] = (uint8_t)(y);
167
52.9k
      return 4;
168
52.9k
    }
169
20.8k
    z[0] = 251;
170
20.8k
    varintWrite32(z+1, y);
171
20.8k
    return 5;
172
20.8k
  }
173
101k
  if (w <= 255) {
174
541
    z[0] = 252;
175
541
    z[1] = (uint8_t)w;
176
541
    varintWrite32(z+2, y);
177
541
    return 6;
178
541
  }
179
101k
  if (w <= 65535) {
180
523
    z[0] = 253;
181
523
    z[1] = (uint8_t)(w>>8);
182
523
    z[2] = (uint8_t)w;
183
523
    varintWrite32(z+3, y);
184
523
    return 7;
185
523
  }
186
100k
  if (w <= 16777215) {
187
2.13k
    z[0] = 254;
188
2.13k
    z[1] = (uint8_t)(w>>16);
189
2.13k
    z[2] = (uint8_t)(w>>8);
190
2.13k
    z[3] = (uint8_t)w;
191
2.13k
    varintWrite32(z+4, y);
192
2.13k
    return 8;
193
2.13k
  }
194
98.6k
  z[0] = 255;
195
98.6k
  varintWrite32(z+1, w);
196
98.6k
  varintWrite32(z+5, y);
197
98.6k
  return 9;
198
98.6k
}
199
200
// Decode the varint in the first n bytes z[].  Write the integer value
201
// into *pResult and return the number of bytes in the varint.
202
//
203
// If the decode fails because there are not enough bytes in z[] then
204
// return 0;
205
//
206
// Borrowed from sqlite4 varint.c
207
static int sqlite4GetVarint64(
208
  const uint8_t *z,
209
  size_t n,
210
200k
  uint64_t *pResult) {
211
200k
  unsigned int x;
212
200k
  if ( n < 1) return 0;
213
200k
  if (z[0] <= 240) {
214
241
    *pResult = z[0];
215
241
    return 1;
216
241
  }
217
199k
  if (z[0] <= 248) {
218
2.04k
    if ( n < 2) return 0;
219
2.04k
    *pResult = (z[0]-241)*256 + z[1] + 240;
220
2.04k
    return 2;
221
2.04k
  }
222
197k
  if (n < z[0]-246U ) return 0;
223
197k
  if (z[0] == 249) {
224
65.5k
    *pResult = 2288 + 256*z[1] + z[2];
225
65.5k
    return 3;
226
65.5k
  }
227
132k
  if (z[0] == 250) {
228
32.1k
    *pResult = (z[1] << 16) + (z[2] << 8) + z[3];
229
32.1k
    return 4;
230
32.1k
  }
231
100k
  x = (z[1] << 24) + (z[2] << 16) + (z[3] << 8) + z[4];
232
100k
  if (z[0] == 251) {
233
0
    *pResult = x;
234
0
    return 5;
235
0
  }
236
100k
  if (z[0] == 252) {
237
0
    *pResult = (((uint64_t)x) << 8) + z[5];
238
0
    return 6;
239
0
  }
240
100k
  if (z[0] == 253) {
241
6
    *pResult = (((uint64_t)x) << 16) + (z[5] << 8) + z[6];
242
6
    return 7;
243
6
  }
244
99.9k
  if (z[0] == 254) {
245
1.62k
    *pResult = (((uint64_t)x) << 24) + (z[5] << 16) + (z[6] << 8) + z[7];
246
1.62k
    return 8;
247
1.62k
  }
248
98.3k
  *pResult = (((uint64_t)x) << 32) +
249
98.3k
               (0xffffffff & ((z[5] << 24) + (z[6] << 16) + (z[7] << 8) + z[8]));
250
98.3k
  return 9;
251
98.3k
}
252
253
////////////////////////////////////////////////////////////
254
// End code ripped from sqlite4
255
////////////////////////////////////////////////////////////
256
257
305k
size_t PutVarint64ToBuf(uint8_t* buf, size_t bufsize, uint64_t value) {
258
305k
  auto used = sqlite4PutVarint64(buf, value);
259
305k
  DCHECK_LE(used, bufsize);
260
305k
  return used;
261
305k
}
262
263
0
void PutMemcmpableVarint64(std::string *dst, uint64_t value) {
264
0
  uint8_t buf[16];
265
0
  auto used = PutVarint64ToBuf(buf, sizeof(buf), value);
266
0
  dst->append(to_char_ptr(buf), used);
267
0
}
268
269
305k
void PutMemcmpableVarint64(faststring *dst, uint64_t value) {
270
305k
  uint8_t buf[16];
271
305k
  auto used = PutVarint64ToBuf(buf, sizeof(buf), value);
272
305k
  dst->append(buf, used);
273
305k
}
274
275
200k
Status GetMemcmpableVarint64(Slice *input, uint64_t *value) {
276
200k
  size_t size = sqlite4GetVarint64(input->data(), input->size(), value);
277
200k
  input->remove_prefix(size);
278
200k
  if (size <= 0) {
279
0
    return STATUS(InvalidArgument, "Valid varint couldn't be decoded");
280
0
  }
281
200k
  return Status::OK();
282
200k
}
283
284
} // namespace yb