• 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/Collection.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 <string>
26
#include <string_view>
27
#include <unordered_map>
28

29
#include "velocypack/velocypack-common.h"
30
#include "velocypack/Collection.h"
31
#include "velocypack/Iterator.h"
32
#include "velocypack/Slice.h"
33
#include "velocypack/Value.h"
34
#include "velocypack/ValueType.h"
35

36
using namespace arangodb::velocypack;
37

38
// fully append an array to the builder
39
Builder& Collection::appendArray(Builder& builder, Slice slice) {
×
40
  ArrayIterator it(slice);
×
41

42
  while (it.valid()) {
×
43
    builder.add(it.value());
×
44
    it.next();
×
45
  }
46

47
  return builder;
×
48
}
49

50
// convert a vector of strings into an unordered_set of strings
51
static inline std::unordered_set<std::string> makeSet(
×
52
    std::vector<std::string> const& keys) {
53
  std::unordered_set<std::string> s;
×
54
  for (auto const& it : keys) {
×
55
    s.emplace(it);
×
56
  }
57
  return s;
×
58
}
59

60
void Collection::forEach(Slice slice, Predicate const& predicate) {
×
61
  ArrayIterator it(slice);
×
62
  ValueLength index = 0;
×
63

64
  while (it.valid()) {
×
65
    if (!predicate(it.value(), index)) {
×
66
      // abort
67
      return;
×
68
    }
69
    it.next();
×
70
    ++index;
×
71
  }
72
}
73

74
Builder Collection::filter(Slice slice, Predicate const& predicate) {
×
75
  // construct a new Array
76
  Builder b;
×
77
  b.add(Value(ValueType::Array));
×
78

79
  ArrayIterator it(slice);
×
80
  ValueLength index = 0;
×
81

82
  while (it.valid()) {
×
83
    Slice s = it.value();
×
84
    if (predicate(s, index)) {
×
85
      b.add(s);
×
86
    }
87
    it.next();
×
88
    ++index;
×
89
  }
90
  b.close();
×
91
  return b;
×
92
}
93

94
Slice Collection::find(Slice slice, Predicate const& predicate) {
×
95
  ArrayIterator it(slice);
×
96
  ValueLength index = 0;
×
97

98
  while (it.valid()) {
×
99
    Slice s = it.value();
×
100
    if (predicate(s, index)) {
×
101
      return s;
×
102
    }
103
    it.next();
×
104
    ++index;
×
105
  }
106

107
  return Slice();
×
108
}
109

110
bool Collection::contains(Slice slice, Predicate const& predicate) {
×
111
  ArrayIterator it(slice);
×
112
  ValueLength index = 0;
×
113

114
  while (it.valid()) {
×
115
    Slice s = it.value();
×
116
    if (predicate(s, index)) {
×
117
      return true;
×
118
    }
119
    it.next();
×
120
    ++index;
×
121
  }
122

123
  return false;
×
124
}
125

126
bool Collection::contains(Slice slice, Slice other) {
×
127
  ArrayIterator it(slice);
×
128

129
  while (it.valid()) {
×
130
    if (it.value().binaryEquals(other)) {
×
131
      return true;
×
132
    }
133
    it.next();
×
134
  }
135

136
  return false;
×
137
}
138

139
ValueLength Collection::indexOf(Slice slice, Slice other) {
×
140
  ArrayIterator it(slice);
×
141
  ValueLength index = 0;
×
142

143
  while (it.valid()) {
×
144
    if (it.value().binaryEquals(other)) {
×
145
      return index;
×
146
    }
147
    it.next();
×
148
    ++index;
×
149
  }
150

151
  return Collection::NotFound;
×
152
}
153

154
bool Collection::all(Slice slice, Predicate const& predicate) {
×
155
  ArrayIterator it(slice);
×
156
  ValueLength index = 0;
×
157

158
  while (it.valid()) {
×
159
    Slice s = it.value();
×
160
    if (!predicate(s, index)) {
×
161
      return false;
×
162
    }
163
    it.next();
×
164
    ++index;
×
165
  }
166

167
  return true;
×
168
}
169

170
bool Collection::any(Slice slice, Predicate const& predicate) {
×
171
  ArrayIterator it(slice);
×
172
  ValueLength index = 0;
×
173

174
  while (it.valid()) {
×
175
    Slice s = it.value();
×
176
    if (predicate(s, index)) {
×
177
      return true;
×
178
    }
179
    it.next();
×
180
    ++index;
×
181
  }
182

183
  return false;
×
184
}
185

186
std::vector<std::string> Collection::keys(Slice slice) {
×
187
  std::vector<std::string> result;
×
188

189
  keys(slice, result);
×
190

191
  return result;
×
192
}
193

194
Builder Collection::concat(Slice slice1, Slice slice2) {
×
195
  Builder b;
×
196
  b.openArray();
×
197
  appendArray(b, slice1);
×
198
  appendArray(b, slice2);
×
199
  b.close();
×
200

201
  return b;
×
202
}
203

204
Builder Collection::extract(Slice slice, int64_t from, int64_t to) {
×
205
  Builder b;
×
206
  b.openArray();
×
207

208
  int64_t length = static_cast<int64_t>(slice.length());
×
209
  int64_t skip = from;
×
210
  int64_t limit = to;
×
211

212
  if (limit < 0) {
×
213
    limit = length + limit - skip;
×
214
  }
215
  if (limit > 0) {
×
216
    ArrayIterator it(slice);
×
217
    while (it.valid()) {
×
218
      if (skip > 0) {
×
219
        --skip;
×
220
      } else {
221
        b.add(it.value());
×
222
        if (--limit == 0) {
×
223
          break;
×
224
        }
225
      }
226
      it.next();
×
227
    }
228
  }
229
  b.close();
×
230

231
  return b;
×
232
}
233

234
Builder Collection::values(Slice slice) {
×
235
  Builder b;
×
236
  b.add(Value(ValueType::Array));
×
237

238
  ObjectIterator it(slice, /*useSequentialIteration*/ false);
×
239

240
  while (it.valid()) {
×
241
    b.add(it.value());
×
242
    it.next();
×
243
  }
244

245
  b.close();
×
246
  return b;
×
247
}
248

249
Builder Collection::keep(Slice slice,
×
250
                         std::vector<std::string> const& keys) {
251
  // check if there are so many keys that we want to use the hash-based version
252
  // cut-off values are arbitrary...
253
  if (keys.size() >= 4 && slice.length() > 10) {
×
254
    return keep(slice, makeSet(keys));
×
255
  }
256

257
  Builder b;
×
258
  b.add(Value(ValueType::Object));
×
259

260
  ObjectIterator it(slice, /*useSequentialIteration*/ false);
×
261

262
  while (it.valid()) {
×
263
    auto key = it.key(true).copyString();
×
264
    if (std::find(keys.begin(), keys.end(), key) != keys.end()) {
×
265
      b.add(key, it.value());
×
266
    }
267
    it.next();
×
268
  }
269

270
  b.close();
×
271
  return b;
×
272
}
273

274
Builder Collection::keep(Slice slice,
×
275
                         std::unordered_set<std::string> const& keys) {
276
  Builder b;
×
277
  b.add(Value(ValueType::Object));
×
278

279
  ObjectIterator it(slice, /*useSequentialIteration*/ false);
×
280

281
  while (it.valid()) {
×
282
    auto key = it.key(true).copyString();
×
283
    if (keys.find(key) != keys.end()) {
×
284
      b.add(key, it.value());
×
285
    }
286
    it.next();
×
287
  }
288

289
  b.close();
×
290
  return b;
×
291
}
292

293
Builder Collection::remove(Slice slice,
×
294
                           std::vector<std::string> const& keys) {
295
  // check if there are so many keys that we want to use the hash-based version
296
  // cut-off values are arbitrary...
297
  if (keys.size() >= 4 && slice.length() > 10) {
×
298
    return remove(slice, makeSet(keys));
×
299
  }
300

301
  Builder b;
×
302
  b.add(Value(ValueType::Object));
×
303

304
  ObjectIterator it(slice, /*useSequentialIteration*/ false);
×
305

306
  while (it.valid()) {
×
307
    auto key = it.key(true).copyString();
×
308
    if (std::find(keys.begin(), keys.end(), key) == keys.end()) {
×
309
      b.add(key, it.value());
×
310
    }
311
    it.next();
×
312
  }
313

314
  b.close();
×
315
  return b;
×
316
}
317

318
Builder Collection::remove(Slice slice,
×
319
                           std::unordered_set<std::string> const& keys) {
320
  Builder b;
×
321
  b.add(Value(ValueType::Object));
×
322

323
  ObjectIterator it(slice, /*useSequentialIteration*/ false);
×
324

325
  while (it.valid()) {
×
326
    auto key = it.key(true).copyString();
×
327
    if (keys.find(key) == keys.end()) {
×
328
      b.add(key, it.value());
×
329
    }
330
    it.next();
×
331
  }
332

333
  b.close();
×
334
  return b;
×
335
}
336

337
Builder Collection::merge(Slice left, Slice right,
×
338
                          bool mergeValues, bool nullMeansRemove) {
339
  if (!left.isObject() || !right.isObject()) {
×
340
    throw Exception(Exception::InvalidValueType, "Expecting type Object");
×
341
  }
342

343
  Builder b;
×
344
  Collection::merge(b, left, right, mergeValues, nullMeansRemove);
×
345
  return b;
×
346
}
347

348
Builder& Collection::merge(Builder& builder, Slice left,
×
349
                           Slice right, bool mergeValues,
350
                           bool nullMeansRemove) {
351
  if (!left.isObject() || !right.isObject()) {
×
352
    throw Exception(Exception::InvalidValueType, "Expecting type Object");
×
353
  }
354

355
  builder.add(Value(ValueType::Object));
×
356

357
  std::unordered_map<std::string_view, Slice> rightValues;
×
358
  {
359
    ObjectIterator it(right, /*useSequentialIteration*/ true);
×
360
    while (it.valid()) {
×
361
      auto current = (*it);
×
362
      rightValues.emplace(current.key.stringView(), current.value);
×
363
      it.next();
×
364
    }
365
  }
366

367
  {
368
    ObjectIterator it(left, /*useSequentialIteration*/ false);
×
369

370
    while (it.valid()) {
×
371
      auto current = (*it);
×
372
      auto key = current.key.stringView();
×
373
      auto found = rightValues.find(key);
×
374

375
      if (found == rightValues.end()) {
×
376
        // use left value
377
        builder.add(key, current.value);
×
378
      } else if (mergeValues && current.value.isObject() &&
×
379
                 (*found).second.isObject()) {
×
380
        // merge both values
381
        auto& value = (*found).second;
×
382
        if (!nullMeansRemove || (!value.isNone() && !value.isNull())) {
×
383
          builder.add(Value(key));
×
384
          Collection::merge(builder, current.value, value, true,
385
                            nullMeansRemove);
×
386
        }
387
        // clear the value in the map so its not added again
388
        (*found).second = Slice();
×
389
      } else {
390
        // use right value
391
        auto& value = (*found).second;
×
392
        if (!nullMeansRemove || (!value.isNone() && !value.isNull())) {
×
393
          builder.add(key, value);
×
394
        }
395
        // clear the value in the map so its not added again
396
        (*found).second = Slice();
×
397
      }
398
      it.next();
×
399
    }
400
  }
401

402
  // add remaining values that were only in right
403
  for (auto& it : rightValues) {
×
404
    auto& s = it.second;
×
405
    if (s.isNone()) {
×
406
      continue;
×
407
    }
408
    if (nullMeansRemove && s.isNull()) {
×
409
      continue;
×
410
    }
411
    builder.add(std::move(it.first), s);
×
412
  }
413

414
  builder.close();
×
415
  return builder;
×
416
}
417

418
template<Collection::VisitationOrder order>
419
static bool doVisit(
420
    Slice slice,
421
    std::function<bool(Slice key, Slice value)> const& func);
422

423
template<Collection::VisitationOrder order>
424
static bool visitObject(
×
425
    Slice value,
426
    std::function<bool(Slice key, Slice value)> const& func) {
427
  ObjectIterator it(value, /*useSequentialIteration*/ false);
×
428

429
  while (it.valid()) {
×
430
    auto current = (*it);
×
431
    // sub-object?
432
    Slice v = current.value;
×
433
    bool const isCompound = (v.isObject() || v.isArray());
×
434

435
    if (isCompound && order == Collection::PreOrder) {
×
436
      if (!doVisit<order>(v, func)) {
×
437
        return false;
×
438
      }
439
    }
440

441
    if (!func(current.key, v)) {
×
442
      return false;
×
443
    }
444

445
    if (isCompound && order == Collection::PostOrder) {
×
446
      if (!doVisit<order>(v, func)) {
×
447
        return false;
×
448
      }
449
    }
450

451
    it.next();
×
452
  }
453
  return true;
×
454
}
455

456
template<Collection::VisitationOrder order>
457
static bool visitArray(
×
458
    Slice value,
459
    std::function<bool(Slice key, Slice value)> const& func) {
460
  ArrayIterator it(value);
×
461

462
  while (it.valid()) {
×
463
    // sub-object?
464
    Slice v = it.value();
×
465
    bool const isCompound = (v.isObject() || v.isArray());
×
466

467
    if (isCompound && order == Collection::PreOrder) {
×
468
      if (!doVisit<order>(v, func)) {
×
469
        return false;
×
470
      }
471
    }
472

473
    if (!func(Slice(), v)) {
×
474
      return false;
×
475
    }
476

477
    if (isCompound && order == Collection::PostOrder) {
×
478
      if (!doVisit<order>(v, func)) {
×
479
        return false;
×
480
      }
481
    }
482

483
    it.next();
×
484
  }
485

486
  return true;
×
487
}
488

489
template<Collection::VisitationOrder order>
490
static bool doVisit(
×
491
    Slice slice,
492
    std::function<bool(Slice key, Slice value)> const& func) {
493
  if (slice.isObject()) {
×
494
    return visitObject<order>(slice, func);
×
495
  }
496
  if (slice.isArray()) {
×
497
    return visitArray<order>(slice, func);
×
498
  }
499

500
  throw Exception(Exception::InvalidValueType,
×
501
                  "Expecting type Object or Array");
502
}
503

504
void Collection::visitRecursive(
×
505
    Slice slice, Collection::VisitationOrder order,
506
    std::function<bool(Slice, Slice)> const& func) {
507
  if (order == Collection::PreOrder) {
×
508
    doVisit<Collection::PreOrder>(slice, func);
×
509
  } else {
510
    doVisit<Collection::PostOrder>(slice, func);
×
511
  }
512
}
×
513

514
Builder Collection::sort(
×
515
    Slice array,
516
    std::function<bool(Slice, Slice)> lessthan) {
517
  if (!array.isArray()) {
×
518
    throw Exception(Exception::InvalidValueType, "Expecting type Array");
×
519
  }
520
  std::vector<Slice> subValues;
×
521
  ValueLength len = array.length();
×
522
  subValues.reserve(checkOverflow(len));
×
523
  for (ValueLength i = 0; i < len; i++) {
×
524
    subValues.push_back(array[i]);
×
525
  }
526
  std::sort(subValues.begin(), subValues.end(), lessthan);
×
527
  Builder b;
×
528
  b.openArray();
×
529
  for (auto const& s : subValues) {
×
530
    b.add(s);
×
531
  }
532
  b.close();
×
533
  return b;
×
534
}
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