• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

arangodb / velocypack / 3998645281

pending completion
3998645281

Pull #148

github

GitHub
Merge b1e3c924b into 5a28b6413
Pull Request #148: use separate namespace for xxh functions

0 of 5107 relevant lines covered (0.0%)

0.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Slice.cpp
1
////////////////////////////////////////////////////////////////////////////////
2
/// DISCLAIMER
3
///
4
/// Copyright 2014-2020 ArangoDB GmbH, Cologne, Germany
5
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
6
///
7
/// Licensed under the Apache License, Version 2.0 (the "License");
8
/// you may not use this file except in compliance with the License.
9
/// You may obtain a copy of the License at
10
///
11
///     http://www.apache.org/licenses/LICENSE-2.0
12
///
13
/// Unless required by applicable law or agreed to in writing, software
14
/// distributed under the License is distributed on an "AS IS" BASIS,
15
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
/// See the License for the specific language governing permissions and
17
/// limitations under the License.
18
///
19
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
20
///
21
/// @author Max Neunhoeffer
22
/// @author Jan Steemann
23
////////////////////////////////////////////////////////////////////////////////
24

25
#include <ostream>
26

27
#include "velocypack/velocypack-common.h"
28
#include "velocypack/AttributeTranslator.h"
29
#include "velocypack/Builder.h"
30
#include "velocypack/Dumper.h"
31
#include "velocypack/HexDump.h"
32
#include "velocypack/Iterator.h"
33
#include "velocypack/Parser.h"
34
#include "velocypack/Sink.h"
35
#include "velocypack/Slice.h"
36
#include "velocypack/ValueType.h"
37

38
using namespace arangodb::velocypack;
39

40
namespace {
41

42
// maximum values for integers of different byte sizes
43
constexpr int64_t maxValues[] = {
44
    128,          32768,           8388608,          2147483648,
45
    549755813888, 140737488355328, 36028797018963968};
46

47
}  // namespace
48

49
uint8_t const Slice::noneSliceData[] = {0x00};
50
uint8_t const Slice::illegalSliceData[] = {0x17};
51
uint8_t const Slice::nullSliceData[] = {0x18};
52
uint8_t const Slice::falseSliceData[] = {0x19};
53
uint8_t const Slice::trueSliceData[] = {0x1a};
54
uint8_t const Slice::zeroSliceData[] = {0x30};
55
uint8_t const Slice::emptyStringSliceData[] = {0x40};
56
uint8_t const Slice::emptyArraySliceData[] = {0x01};
57
uint8_t const Slice::emptyObjectSliceData[] = {0x0a};
58
uint8_t const Slice::minKeySliceData[] = {0x1e};
59
uint8_t const Slice::maxKeySliceData[] = {0x1f};
60

61
// translates an integer key into a string
62
Slice Slice::translate() const {
×
63
  if (VELOCYPACK_UNLIKELY(!isSmallInt() && !isUInt())) {
×
64
    throw Exception(Exception::InvalidValueType,
×
65
                    "Cannot translate key of this type");
×
66
  }
67
  if (Options::Defaults.attributeTranslator == nullptr) {
×
68
    throw Exception(Exception::NeedAttributeTranslator);
×
69
  }
70
  return translateUnchecked();
×
71
}
72

73
// return the value for a UInt object, without checks!
74
// returns 0 for invalid values/types
75
uint64_t Slice::getUIntUnchecked() const noexcept {
×
76
  uint8_t const h = head();
×
77
  if (h >= 0x28 && h <= 0x2f) {
×
78
    // UInt
79
    return readIntegerNonEmpty<uint64_t>(start() + 1, h - 0x27);
×
80
  }
81

82
  if (h >= 0x30 && h <= 0x39) {
×
83
    // Smallint >= 0
84
    return static_cast<uint64_t>(h - 0x30);
×
85
  }
86
  return 0;
×
87
}
88

89
// return the value for a SmallInt object
90
int64_t Slice::getSmallIntUnchecked() const noexcept {
×
91
  uint8_t const h = head();
×
92

93
  if (h >= 0x30 && h <= 0x39) {
×
94
    // Smallint >= 0
95
    return static_cast<int64_t>(h - 0x30);
×
96
  }
97

98
  if (h >= 0x3a && h <= 0x3f) {
×
99
    // Smallint < 0
100
    return static_cast<int64_t>(h - 0x3a) - 6;
×
101
  }
102

103
  if ((h >= 0x20 && h <= 0x27) || (h >= 0x28 && h <= 0x2f)) {
×
104
    // Int and UInt
105
    // we'll leave it to the compiler to detect the two ranges above are
106
    // adjacent
107
    return getIntUnchecked();
×
108
  }
109

110
  return 0;
×
111
}
112

113
// translates an integer key into a string, without checks
114
Slice Slice::translateUnchecked() const {
×
115
  uint8_t const* result =
116
      Options::Defaults.attributeTranslator->translate(getUIntUnchecked());
×
117
  if (VELOCYPACK_LIKELY(result != nullptr)) {
×
118
    return Slice(result);
×
119
  }
120
  return Slice();
×
121
}
122

123
std::string Slice::toHex() const {
×
124
  HexDump dump(*this);
×
125
  return dump.toString();
×
126
}
127

128
std::string Slice::toJson(Options const* options) const {
×
129
  std::string buffer;
×
130
  StringSink sink(&buffer);
×
131
  toJson(&sink, options);
×
132
  return buffer;
×
133
}
134

135
std::string& Slice::toJson(std::string& out, Options const* options) const {
×
136
  // reserve some initial space in the output string to avoid
137
  // later reallocations. we use the Slice's byteSize as a first
138
  // approximation for the needed output buffer size.
139
  out.reserve(out.size() + byteSize());
×
140
  StringSink sink(&out);
×
141
  toJson(&sink, options);
×
142
  return out;
×
143
}
144

145
void Slice::toJson(Sink* sink, Options const* options) const {
×
146
  Dumper dumper(sink, options);
×
147
  dumper.dump(*this);
×
148
}
×
149

150
std::string Slice::toString(Options const* options) const {
×
151
  if (isString()) {
×
152
    return copyString();
×
153
  }
154

155
  // copy options and set prettyPrint in copy
156
  Options prettyOptions = *options;
×
157
  prettyOptions.prettyPrint = true;
×
158

159
  std::string buffer;
×
160
  // reserve some initial space in the output string to avoid
161
  // later reallocations. we use the Slice's byteSize as a first
162
  // approximation for the needed output buffer size.
163
  buffer.reserve(buffer.size() + byteSize());
×
164

165
  StringSink sink(&buffer);
×
166
  Dumper::dump(this, &sink, &prettyOptions);
×
167
  return buffer;
×
168
}
169

170
std::string Slice::hexType() const { return HexDump::toHex(head()); }
×
171

172
uint64_t Slice::normalizedHash(uint64_t seed) const {
×
173
  uint64_t value;
174

175
  if (isNumber()) {
×
176
    // upcast integer values to double
177
    double v = getNumericValue<double>();
×
178
    value = VELOCYPACK_HASH(&v, sizeof(v), seed);
×
179
  } else if (isArray()) {
×
180
    // normalize arrays by hashing array length and iterating
181
    // over all array members
182
    ArrayIterator it(*this);
×
183
    uint64_t const n = it.size() ^ 0xba5bedf00d;
×
184
    value = VELOCYPACK_HASH(&n, sizeof(n), seed);
×
185
    while (it.valid()) {
×
186
      value ^= it.value().normalizedHash(value);
×
187
      it.next();
×
188
    }
189
  } else if (isObject()) {
×
190
    // normalize objects by hashing object length and iterating
191
    // over all object members
192
    ObjectIterator it(*this, true);
×
193
    uint64_t const n = it.size() ^ 0xf00ba44ba5;
×
194
    uint64_t seed2 = VELOCYPACK_HASH(&n, sizeof(n), seed);
×
195
    value = seed2;
×
196
    while (it.valid()) {
×
197
      auto current = (*it);
×
198
      uint64_t seed3 = current.key.normalizedHash(seed2);
×
199
      value ^= seed3;
×
200
      value ^= current.value.normalizedHash(seed3);
×
201
      it.next();
×
202
    }
203
  } else {
204
    // fall back to regular hash function
205
    value = hash(seed);
×
206
  }
207

208
  return value;
×
209
}
210

211
uint32_t Slice::normalizedHash32(uint32_t seed) const {
×
212
  uint32_t value;
213

214
  if (isNumber()) {
×
215
    // upcast integer values to double
216
    double v = getNumericValue<double>();
×
217
    value = VELOCYPACK_HASH32(&v, sizeof(v), seed);
×
218
  } else if (isArray()) {
×
219
    // normalize arrays by hashing array length and iterating
220
    // over all array members
221
    ArrayIterator it(*this);
×
222
    uint64_t const n = it.size() ^ 0xba5bedf00d;
×
223
    value = VELOCYPACK_HASH32(&n, sizeof(n), seed);
×
224
    while (it.valid()) {
×
225
      value ^= it.value().normalizedHash32(value);
×
226
      it.next();
×
227
    }
228
  } else if (isObject()) {
×
229
    // normalize objects by hashing object length and iterating
230
    // over all object members
231
    ObjectIterator it(*this, true);
×
232
    uint32_t const n = static_cast<uint32_t>(it.size() ^ 0xf00ba44ba5);
×
233
    uint32_t seed2 = VELOCYPACK_HASH32(&n, sizeof(n), seed);
×
234
    value = seed2;
×
235
    while (it.valid()) {
×
236
      auto current = (*it);
×
237
      uint32_t seed3 = current.key.normalizedHash32(seed2);
×
238
      value ^= seed3;
×
239
      value ^= current.value.normalizedHash32(seed3);
×
240
      it.next();
×
241
    }
242
  } else {
243
    // fall back to regular hash function
244
    value = hash32(seed);
×
245
  }
246

247
  return value;
×
248
}
249

250
// look for the specified attribute inside an Object
251
// returns a Slice(ValueType::None) if not found
252
Slice Slice::get(std::string_view attribute) const {
×
253
  if (VELOCYPACK_UNLIKELY(!isObject())) {
×
254
    throw Exception(Exception::InvalidValueType, "Expecting Object");
×
255
  }
256

257
  auto const h = head();
×
258
  if (h == 0x0a) {
×
259
    // special case, empty object
260
    return Slice();
×
261
  }
262

263
  if (h == 0x14) {
×
264
    // compact Object
265
    return getFromCompactObject(attribute);
×
266
  }
267

268
  ValueLength const offsetSize = indexEntrySize(h);
×
269
  VELOCYPACK_ASSERT(offsetSize > 0);
×
270
  ValueLength end = readIntegerNonEmpty<ValueLength>(start() + 1, offsetSize);
×
271

272
  // read number of items
273
  ValueLength n;
274
  ValueLength ieBase;
275
  if (offsetSize < 8) {
×
276
    n = readIntegerNonEmpty<ValueLength>(start() + 1 + offsetSize, offsetSize);
×
277
    ieBase = end - n * offsetSize;
×
278
  } else {
279
    n = readIntegerNonEmpty<ValueLength>(start() + end - offsetSize,
×
280
                                         offsetSize);
281
    ieBase = end - n * offsetSize - offsetSize;
×
282
  }
283

284
  if (n == 1) {
×
285
    // Just one attribute, there is no index table!
286
    Slice key(start() + findDataOffset(h));
×
287

288
    if (key.isString()) {
×
289
      if (key.isEqualStringUnchecked(attribute)) {
×
290
        return Slice(key.start() + key.byteSize());
×
291
      }
292
      // fall through to returning None Slice below
293
    } else if (key.isSmallInt() || key.isUInt()) {
×
294
      // translate key
295
      if (Options::Defaults.attributeTranslator == nullptr) {
×
296
        throw Exception(Exception::NeedAttributeTranslator);
×
297
      }
298
      if (key.translateUnchecked().isEqualString(attribute)) {
×
299
        return Slice(key.start() + key.byteSize());
×
300
      }
301
    }
302

303
    // no match or invalid key type
304
    return Slice();
×
305
  }
306

307
  // only use binary search for attributes if we have at least this many entries
308
  // otherwise we'll always use the linear search
309
  constexpr ValueLength SortedSearchEntriesThreshold = 4;
×
310

311
  if (n >= SortedSearchEntriesThreshold && (h >= 0x0b && h <= 0x0e)) {
×
312
    switch (offsetSize) {
×
313
      case 1:
×
314
        return searchObjectKeyBinary<1>(attribute, ieBase, n);
×
315
      case 2:
×
316
        return searchObjectKeyBinary<2>(attribute, ieBase, n);
×
317
      case 4:
×
318
        return searchObjectKeyBinary<4>(attribute, ieBase, n);
×
319
      case 8:
×
320
        return searchObjectKeyBinary<8>(attribute, ieBase, n);
×
321
      default: {
×
322
      }
323
    }
324
  }
325

326
  return searchObjectKeyLinear(attribute, ieBase, offsetSize, n);
×
327
}
328

329
// return the value for an Int object
330
int64_t Slice::getIntUnchecked() const noexcept {
×
331
  uint8_t const h = head();
×
332

333
  if (h >= 0x20 && h <= 0x27) {
×
334
    // Int  T
335
    uint64_t v = readIntegerNonEmpty<uint64_t>(start() + 1, h - 0x1f);
×
336
    if (h == 0x27) {
×
337
      return toInt64(v);
×
338
    } else {
339
      int64_t vv = static_cast<int64_t>(v);
×
340
      int64_t shift = ::maxValues[h - 0x20];
×
341
      return vv < shift ? vv : vv - (shift << 1);
×
342
    }
343
  }
344

345
  // SmallInt
346
  VELOCYPACK_ASSERT(h >= 0x30 && h <= 0x3f);
×
347
  return getSmallIntUnchecked();
×
348
}
349

350
// return the value for an Int object
351
int64_t Slice::getInt() const {
×
352
  uint8_t const h = head();
×
353

354
  if (h >= 0x20 && h <= 0x27) {
×
355
    // Int  T
356
    uint64_t v = readIntegerNonEmpty<uint64_t>(start() + 1, h - 0x1f);
×
357
    if (h == 0x27) {
×
358
      return toInt64(v);
×
359
    } else {
360
      int64_t vv = static_cast<int64_t>(v);
×
361
      int64_t shift = ::maxValues[h - 0x20];
×
362
      return vv < shift ? vv : vv - (shift << 1);
×
363
    }
364
  }
365

366
  if (h >= 0x28 && h <= 0x2f) {
×
367
    // UInt
368
    uint64_t v = getUIntUnchecked();
×
369
    if (v > static_cast<uint64_t>(INT64_MAX)) {
×
370
      throw Exception(Exception::NumberOutOfRange);
×
371
    }
372
    return static_cast<int64_t>(v);
×
373
  }
374

375
  if (h >= 0x30 && h <= 0x3f) {
×
376
    // SmallInt
377
    return getSmallIntUnchecked();
×
378
  }
379

380
  throw Exception(Exception::InvalidValueType, "Expecting type Int");
×
381
}
382

383
// return the value for a UInt object
384
uint64_t Slice::getUInt() const {
×
385
  uint8_t const h = head();
×
386
  if (h == 0x28) {
×
387
    // single byte integer
388
    return readIntegerFixed<uint64_t, 1>(start() + 1);
×
389
  }
390

391
  if (h >= 0x29 && h <= 0x2f) {
×
392
    // UInt
393
    return readIntegerNonEmpty<uint64_t>(start() + 1, h - 0x27);
×
394
  }
395

396
  if (h >= 0x20 && h <= 0x27) {
×
397
    // Int
398
    int64_t v = getInt();
×
399
    if (v < 0) {
×
400
      throw Exception(Exception::NumberOutOfRange);
×
401
    }
402
    return static_cast<int64_t>(v);
×
403
  }
404

405
  if (h >= 0x30 && h <= 0x39) {
×
406
    // Smallint >= 0
407
    return static_cast<uint64_t>(h - 0x30);
×
408
  }
409

410
  if (h >= 0x3a && h <= 0x3f) {
×
411
    // Smallint < 0
412
    throw Exception(Exception::NumberOutOfRange);
×
413
  }
414

415
  throw Exception(Exception::InvalidValueType, "Expecting type UInt");
×
416
}
417

418
// return the value for a SmallInt object
419
int64_t Slice::getSmallInt() const {
×
420
  uint8_t const h = head();
×
421

422
  if (h >= 0x30 && h <= 0x39) {
×
423
    // Smallint >= 0
424
    return static_cast<int64_t>(h - 0x30);
×
425
  }
426

427
  if (h >= 0x3a && h <= 0x3f) {
×
428
    // Smallint < 0
429
    return static_cast<int64_t>(h - 0x3a) - 6;
×
430
  }
431

432
  if ((h >= 0x20 && h <= 0x27) || (h >= 0x28 && h <= 0x2f)) {
×
433
    // Int and UInt
434
    // we'll leave it to the compiler to detect the two ranges above are
435
    // adjacent
436
    return getInt();
×
437
  }
438

439
  throw Exception(Exception::InvalidValueType, "Expecting type SmallInt");
×
440
}
441

442
int Slice::compareString(std::string_view value) const {
×
443
  std::size_t const length = value.size();
×
444
  ValueLength keyLength;
445
  char const* k = getString(keyLength);
×
446
  std::size_t const compareLength =
447
      (std::min)(static_cast<std::size_t>(keyLength), length);
×
448
  int res = std::memcmp(k, value.data(), compareLength);
×
449

450
  if (res == 0) {
×
451
    return static_cast<int>(keyLength - length);
×
452
  }
453
  return res;
×
454
}
455

456
int Slice::compareStringUnchecked(std::string_view value) const noexcept {
×
457
  std::size_t const length = value.size();
×
458
  ValueLength keyLength;
459
  char const* k = getStringUnchecked(keyLength);
×
460
  std::size_t const compareLength =
461
      (std::min)(static_cast<std::size_t>(keyLength), length);
×
462
  int res = std::memcmp(k, value.data(), compareLength);
×
463

464
  if (res == 0) {
×
465
    return static_cast<int>(keyLength - length);
×
466
  }
467
  return res;
×
468
}
469

470
bool Slice::isEqualString(std::string_view attribute) const {
×
471
  ValueLength keyLength;
472
  char const* k = getString(keyLength);
×
473
  return (static_cast<std::size_t>(keyLength) == attribute.size()) &&
×
474
         (std::memcmp(k, attribute.data(), attribute.size()) == 0);
×
475
}
476

477
bool Slice::isEqualStringUnchecked(std::string_view attribute) const noexcept {
×
478
  ValueLength keyLength;
479
  char const* k = getStringUnchecked(keyLength);
×
480
  return (static_cast<std::size_t>(keyLength) == attribute.size()) &&
×
481
         (std::memcmp(k, attribute.data(), attribute.size()) == 0);
×
482
}
483

484
Slice Slice::getFromCompactObject(std::string_view attribute) const {
×
485
  ObjectIterator it(*this, /*useSequentialIteration*/ false);
×
486
  while (it.valid()) {
×
487
    Slice key = it.key(false);
×
488
    if (key.makeKey().isEqualString(attribute)) {
×
489
      return Slice(key.start() + key.byteSize());
×
490
    }
491

492
    it.next();
×
493
  }
494
  // not found
495
  return Slice();
×
496
}
497

498
// get the offset for the nth member from an Array or Object type
499
ValueLength Slice::getNthOffset(ValueLength index) const {
×
500
  VELOCYPACK_ASSERT(isArray() || isObject());
×
501

502
  auto const h = head();
×
503

504
  if (h == 0x13 || h == 0x14) {
×
505
    // compact Array or Object
506
    return getNthOffsetFromCompact(index);
×
507
  }
508

509
  if (VELOCYPACK_UNLIKELY(h == 0x01 || h == 0x0a)) {
×
510
    // special case: empty Array or empty Object
511
    throw Exception(Exception::IndexOutOfBounds);
×
512
  }
513

514
  ValueLength const offsetSize = indexEntrySize(h);
×
515
  ValueLength end = readIntegerNonEmpty<ValueLength>(start() + 1, offsetSize);
×
516

517
  ValueLength dataOffset = 0;
×
518

519
  // find the number of items
520
  ValueLength n;
521
  if (h <= 0x05) {  // No offset table or length, need to compute:
×
522
    VELOCYPACK_ASSERT(h != 0x00 && h != 0x01);
×
523
    dataOffset = findDataOffset(h);
×
524
    Slice first(start() + dataOffset);
×
525
    ValueLength s = first.byteSize();
×
526
    if (VELOCYPACK_UNLIKELY(s == 0)) {
×
527
      throw Exception(Exception::InternalError,
×
528
                      "Invalid data for compact object");
×
529
    }
530
    n = (end - dataOffset) / s;
×
531
  } else if (offsetSize < 8) {
×
532
    n = readIntegerNonEmpty<ValueLength>(start() + 1 + offsetSize, offsetSize);
×
533
  } else {
534
    n = readIntegerNonEmpty<ValueLength>(start() + end - offsetSize,
×
535
                                         offsetSize);
536
  }
537

538
  if (index >= n) {
×
539
    throw Exception(Exception::IndexOutOfBounds);
×
540
  }
541

542
  // empty array case was already covered
543
  VELOCYPACK_ASSERT(n > 0);
×
544

545
  if (h <= 0x05 || n == 1) {
×
546
    // no index table, but all array items have the same length
547
    // now fetch first item and determine its length
548
    if (dataOffset == 0) {
×
549
      VELOCYPACK_ASSERT(h != 0x00 && h != 0x01);
×
550
      dataOffset = findDataOffset(h);
×
551
    }
552
    return dataOffset + index * Slice(start() + dataOffset).byteSize();
×
553
  }
554

555
  ValueLength const ieBase =
×
556
      end - n * offsetSize + index * offsetSize - (offsetSize == 8 ? 8 : 0);
×
557
  return readIntegerNonEmpty<ValueLength>(start() + ieBase, offsetSize);
×
558
}
559

560
// extract the nth member from an Array
561
Slice Slice::getNth(ValueLength index) const {
×
562
  VELOCYPACK_ASSERT(isArray());
×
563

564
  return Slice(start() + getNthOffset(index));
×
565
}
566

567
// extract the nth member from an Object
568
Slice Slice::getNthKey(ValueLength index, bool translate) const {
×
569
  VELOCYPACK_ASSERT(type() == ValueType::Object);
×
570

571
  Slice s(start() + getNthOffset(index));
×
572

573
  if (translate) {
×
574
    return s.makeKey();
×
575
  }
576

577
  return s;
×
578
}
579

580
Slice Slice::makeKey() const {
×
581
  if (isString()) {
×
582
    return *this;
×
583
  }
584
  if (isSmallInt() || isUInt()) {
×
585
    if (VELOCYPACK_UNLIKELY(Options::Defaults.attributeTranslator == nullptr)) {
×
586
      throw Exception(Exception::NeedAttributeTranslator);
×
587
    }
588
    return translateUnchecked();
×
589
  }
590

591
  throw Exception(Exception::InvalidValueType,
×
592
                  "Cannot translate key of this type");
×
593
}
594

595
// get the offset for the nth member from a compact Array or Object type
596
ValueLength Slice::getNthOffsetFromCompact(ValueLength index) const {
×
597
  auto const h = head();
×
598
  VELOCYPACK_ASSERT(h == 0x13 || h == 0x14);
×
599

600
  ValueLength end = readVariableValueLength<false>(start() + 1);
×
601
  ValueLength n = readVariableValueLength<true>(start() + end - 1);
×
602
  if (VELOCYPACK_UNLIKELY(index >= n)) {
×
603
    throw Exception(Exception::IndexOutOfBounds);
×
604
  }
605

606
  ValueLength offset = 1 + getVariableValueLength(end);
×
607
  ValueLength current = 0;
×
608
  while (current != index) {
×
609
    uint8_t const* s = start() + offset;
×
610
    offset += Slice(s).byteSize();
×
611
    if (h == 0x14) {
×
612
      offset += Slice(start() + offset).byteSize();
×
613
    }
614
    ++current;
×
615
  }
616
  return offset;
×
617
}
618

619
// perform a linear search for the specified attribute inside an Object
620
Slice Slice::searchObjectKeyLinear(std::string_view attribute,
×
621
                                   ValueLength ieBase, ValueLength offsetSize,
622
                                   ValueLength n) const {
623
  bool const useTranslator = (Options::Defaults.attributeTranslator != nullptr);
×
624

625
  for (ValueLength index = 0; index < n; ++index) {
×
626
    ValueLength offset = ieBase + index * offsetSize;
×
627
    Slice key(start() +
×
628
              readIntegerNonEmpty<ValueLength>(start() + offset, offsetSize));
×
629

630
    if (key.isString()) {
×
631
      if (!key.isEqualStringUnchecked(attribute)) {
×
632
        continue;
×
633
      }
634
    } else if (key.isSmallInt() || key.isUInt()) {
×
635
      // translate key
636
      if (VELOCYPACK_UNLIKELY(!useTranslator)) {
×
637
        // no attribute translator
638
        throw Exception(Exception::NeedAttributeTranslator);
×
639
      }
640
      if (!key.translateUnchecked().isEqualString(attribute)) {
×
641
        continue;
×
642
      }
643
    } else {
644
      // invalid key type
645
      return Slice();
×
646
    }
647

648
    // key is identical. now return value
649
    return Slice(key.start() + key.byteSize());
×
650
  }
651

652
  // nothing found
653
  return Slice();
×
654
}
655

656
// perform a binary search for the specified attribute inside an Object
657
template<ValueLength offsetSize>
658
Slice Slice::searchObjectKeyBinary(std::string_view attribute,
×
659
                                   ValueLength ieBase, ValueLength n) const {
660
  bool const useTranslator = (Options::Defaults.attributeTranslator != nullptr);
×
661
  VELOCYPACK_ASSERT(n > 0);
×
662

663
  int64_t l = 0;
×
664
  int64_t r = static_cast<int64_t>(n) - 1;
×
665
  int64_t index = r / 2;
×
666

667
  do {
×
668
    ValueLength offset = ieBase + index * offsetSize;
×
669
    Slice key(start() +
×
670
              readIntegerFixed<ValueLength, offsetSize>(start() + offset));
×
671

672
    int res;
673
    if (key.isString()) {
×
674
      res = key.compareStringUnchecked(attribute);
×
675
    } else {
676
      VELOCYPACK_ASSERT(key.isSmallInt() || key.isUInt());
×
677
      // translate key
678
      if (VELOCYPACK_UNLIKELY(!useTranslator)) {
×
679
        // no attribute translator
680
        throw Exception(Exception::NeedAttributeTranslator);
×
681
      }
682
      res = key.translateUnchecked().compareString(attribute);
×
683
    }
684

685
    if (res > 0) {
×
686
      r = index - 1;
×
687
    } else if (res == 0) {
×
688
      // found. now return a Slice pointing at the value
689
      return Slice(key.start() + key.byteSize());
×
690
    } else {
691
      l = index + 1;
×
692
    }
693

694
    // determine new midpoint
695
    index = l + ((r - l) / 2);
×
696
  } while (r >= l);
×
697

698
  // not found
699
  return Slice();
×
700
}
701

702
ValueLength Slice::byteSizeDynamic(uint8_t const* start) const {
×
703
  uint8_t h = *start;
×
704

705
  // types with dynamic lengths need special treatment:
706
  switch (type(h)) {
×
707
    case ValueType::Array:
×
708
    case ValueType::Object: {
709
      if (h == 0x13 || h == 0x14) {
×
710
        // compact Array or Object
711
        return readVariableValueLength<false>(start + 1);
×
712
      }
713

714
      VELOCYPACK_ASSERT(h > 0x01 && h <= 0x0e && h != 0x0a);
×
715
      if (VELOCYPACK_UNLIKELY(h >= sizeof(SliceStaticData::WidthMap) /
×
716
                                       sizeof(SliceStaticData::WidthMap[0]))) {
717
        throw Exception(Exception::InternalError, "invalid Array/Object type");
×
718
      }
719
      return readIntegerNonEmpty<ValueLength>(start + 1,
×
720
                                              SliceStaticData::WidthMap[h]);
×
721
    }
722

723
    case ValueType::String: {
×
724
      VELOCYPACK_ASSERT(h == 0xbf);
×
725

726
      if (VELOCYPACK_UNLIKELY(h < 0xbf)) {
×
727
        // we cannot get here, because the FixedTypeLengths lookup
728
        // above will have kicked in already. however, the compiler
729
        // claims we'll be reading across the bounds of the input
730
        // here...
731
        return h - 0x40;
×
732
      }
733

734
      // long UTF-8 String
735
      return static_cast<ValueLength>(
736
          1 + 8 + readIntegerFixed<ValueLength, 8>(start + 1));
×
737
    }
738

739
    case ValueType::Binary: {
×
740
      VELOCYPACK_ASSERT(h >= 0xc0 && h <= 0xc7);
×
741
      return static_cast<ValueLength>(
742
          1 + h - 0xbf + readIntegerNonEmpty<ValueLength>(start + 1, h - 0xbf));
×
743
    }
744

745
    case ValueType::BCD: {
×
746
      if (h <= 0xcf) {
×
747
        // positive BCD
748
        VELOCYPACK_ASSERT(h >= 0xc8 && h < 0xcf);
×
749
        return static_cast<ValueLength>(
750
            1 + h - 0xc7 +
×
751
            readIntegerNonEmpty<ValueLength>(start + 1, h - 0xc7));
×
752
      }
753

754
      // negative BCD
755
      VELOCYPACK_ASSERT(h >= 0xd0 && h < 0xd7);
×
756
      return static_cast<ValueLength>(
757
          1 + h - 0xcf + readIntegerNonEmpty<ValueLength>(start + 1, h - 0xcf));
×
758
    }
759

760
    case ValueType::Tagged: {
×
761
      uint8_t offset = tagsOffset(start);
×
762
      if (VELOCYPACK_UNLIKELY(offset == 0)) {
×
763
        throw Exception(Exception::InternalError,
×
764
                        "Invalid tag data in byteSize()");
×
765
      }
766
      return byteSize(start + offset) + offset;
×
767
    }
768

769
    case ValueType::Custom: {
×
770
      VELOCYPACK_ASSERT(h >= 0xf4);
×
771
      switch (h) {
×
772
        case 0xf4:
×
773
        case 0xf5:
774
        case 0xf6: {
775
          return 2 + readIntegerFixed<ValueLength, 1>(start + 1);
×
776
        }
777

778
        case 0xf7:
×
779
        case 0xf8:
780
        case 0xf9: {
781
          return 3 + readIntegerFixed<ValueLength, 2>(start + 1);
×
782
        }
783

784
        case 0xfa:
×
785
        case 0xfb:
786
        case 0xfc: {
787
          return 5 + readIntegerFixed<ValueLength, 4>(start + 1);
×
788
        }
789

790
        case 0xfd:
×
791
        case 0xfe:
792
        case 0xff: {
793
          return 9 + readIntegerFixed<ValueLength, 8>(start + 1);
×
794
        }
795

796
        default: {
×
797
          // fallthrough intentional
798
        }
799
      }
800
    }
801
    default: {
802
      // fallthrough intentional
803
    }
804
  }
805

806
  throw Exception(Exception::InternalError, "Invalid type for byteSize()");
×
807
}
808

809
// template instanciations for searchObjectKeyBinary
810
template Slice Slice::searchObjectKeyBinary<1>(std::string_view attribute,
811
                                               ValueLength ieBase,
812
                                               ValueLength n) const;
813
template Slice Slice::searchObjectKeyBinary<2>(std::string_view attribute,
814
                                               ValueLength ieBase,
815
                                               ValueLength n) const;
816
template Slice Slice::searchObjectKeyBinary<4>(std::string_view attribute,
817
                                               ValueLength ieBase,
818
                                               ValueLength n) const;
819
template Slice Slice::searchObjectKeyBinary<8>(std::string_view attribute,
820
                                               ValueLength ieBase,
821
                                               ValueLength n) const;
822

823
std::ostream& operator<<(std::ostream& stream, Slice const* slice) {
×
824
  stream << "[Slice " << valueTypeName(slice->type()) << " ("
825
         << slice->hexType() << "), byteSize: " << slice->byteSize() << "]";
×
826
  return stream;
×
827
}
828

829
std::ostream& operator<<(std::ostream& stream, Slice const& slice) {
×
830
  return operator<<(stream, &slice);
×
831
}
832

833
static_assert(sizeof(arangodb::velocypack::Slice) == sizeof(void*),
834
              "Slice has an unexpected size");
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc