1
0
Fork 0

Feature/velocypack update (#6678)

This commit is contained in:
Jan 2018-10-02 14:04:14 +02:00 committed by GitHub
parent 883a2baace
commit c06f2d77da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 330 additions and 207 deletions

View File

@ -229,6 +229,8 @@ class Buffer {
return append(value.data(), value.size());
}
// reserves len *extra* bytes of storage space
// this should probably be renamed to reserveExtra
inline void reserve(ValueLength len) {
VELOCYPACK_ASSERT(_size <= _capacity);
@ -255,8 +257,8 @@ class Buffer {
// need reallocation
ValueLength newLen = _size + len;
static constexpr double growthFactor = 1.25;
if (_size > 0 && newLen < growthFactor * _size) {
constexpr double growthFactor = 1.25;
if (newLen < growthFactor * _size) {
// ensure the buffer grows sensibly and not by 1 byte only
newLen = static_cast<ValueLength>(growthFactor * _size);
}

View File

@ -114,15 +114,6 @@ class Builder {
bool _keyWritten; // indicates that in the current object the key
// has been written but the value not yet
// Sort the indices by attribute name:
static void doActualSort(std::vector<SortEntry>& entries);
// Find the actual bytes of the attribute name of the VPack value
// at position base, also determine the length len of the attribute.
// This takes into account the different possibilities for the format
// of attribute names:
static uint8_t const* findAttrName(uint8_t const* base, uint64_t& len);
void sortObjectIndexShort(uint8_t* objBase,
std::vector<ValueLength>& offsets) const;
@ -130,7 +121,13 @@ class Builder {
std::vector<ValueLength>& offsets);
void sortObjectIndex(uint8_t* objBase,
std::vector<ValueLength>& offsets);
std::vector<ValueLength>& offsets) {
if (offsets.size() > 32) {
sortObjectIndexLong(objBase, offsets);
} else {
sortObjectIndexShort(objBase, offsets);
}
}
public:
Options const* options;
@ -573,7 +570,7 @@ class Builder {
private:
inline void checkKeyIsString(bool isString) {
if (!_stack.empty()) {
ValueLength const tos = _stack.back();
ValueLength const& tos = _stack.back();
if (_start[tos] == 0x0b || _start[tos] == 0x14) {
if (!_keyWritten && !isString) {
throw Exception(Exception::BuilderKeyMustBeString);
@ -615,7 +612,7 @@ class Builder {
uint8_t* addInternal(std::string const& attrName, T const& sub) {
bool haveReported = false;
if (!_stack.empty()) {
ValueLength& tos = _stack.back();
ValueLength const& tos = _stack.back();
if (_start[tos] != 0x0b && _start[tos] != 0x14) {
throw Exception(Exception::BuilderNeedOpenObject);
}

View File

@ -39,29 +39,10 @@
#include "velocypack/velocypack-common.h"
#include "velocypack/Exception.h"
#include "velocypack/Options.h"
#include "velocypack/StringRef.h"
#include "velocypack/Value.h"
#include "velocypack/ValueType.h"
#ifndef VELOCYPACK_XXHASH
#ifndef VELOCYPACK_FASTHASH
#define VELOCYPACK_XXHASH
#endif
#endif
#ifdef VELOCYPACK_XXHASH
// forward for XXH64 function declared elsewhere
extern "C" unsigned long long XXH64(void const*, size_t, unsigned long long);
#define VELOCYPACK_HASH(mem, size, seed) XXH64(mem, size, seed)
#endif
#ifdef VELOCYPACK_FASTHASH
// forward for fasthash64 function declared elsewhere
uint64_t fasthash64(void const*, size_t, uint64_t);
#define VELOCYPACK_HASH(mem, size, seed) fasthash64(mem, size, seed)
#endif
namespace arangodb {
namespace velocypack {
@ -185,6 +166,13 @@ class Slice {
return VELOCYPACK_HASH(start(), size, seed);
}
// hashes the binary representation of a value, not using precalculated hash values
// this is mainly here for testing purposes
inline uint64_t hashSlow(uint64_t seed = defaultSeed) const {
size_t const size = checkOverflow(byteSize());
return VELOCYPACK_HASH(start(), size, seed);
}
// hashes the value, normalizing different representations of
// arrays, objects and numbers. this function may produce different
// hash values than the binary hash() function
@ -447,7 +435,8 @@ class Slice {
// look for the specified attribute path inside an Object
// returns a Slice(ValueType::None) if not found
Slice get(std::vector<std::string> const& attributes,
template<typename T>
Slice get(std::vector<T> const& attributes,
bool resolveExternals = false) const {
size_t const n = attributes.size();
if (n == 0) {
@ -476,48 +465,47 @@ class Slice {
return last;
}
// look for the specified attribute path inside an Object
// returns a Slice(ValueType::None) if not found
Slice get(std::vector<char const*> const& attributes) const {
size_t const n = attributes.size();
if (n == 0) {
throw Exception(Exception::InvalidAttributePath);
}
// use ourselves as the starting point
Slice last = Slice(start());
for (size_t i = 0; i < attributes.size(); ++i) {
// fetch subattribute
last = last.get(attributes[i]);
// abort as early as possible
if (last.isNone() || (i + 1 < n && !last.isObject())) {
return Slice();
}
}
return last;
}
// look for the specified attribute inside an Object
// returns a Slice(ValueType::None) if not found
Slice get(std::string const& attribute) const;
Slice get(StringRef const& attribute) const;
Slice get(std::string const& attribute) const {
return get(StringRef(attribute.data(), attribute.size()));
}
// look for the specified attribute inside an Object
// returns a Slice(ValueType::None) if not found
Slice get(char const* attribute) const {
return get(std::string(attribute));
return get(StringRef(attribute));
}
Slice operator[](std::string const& attribute) const {
Slice get(char const* attribute, size_t length) const {
return get(StringRef(attribute, length));
}
Slice operator[](StringRef const& attribute) const {
return get(attribute);
}
Slice operator[](std::string const& attribute) const {
return get(attribute.data(), attribute.size());
}
// whether or not an Object has a specific key
bool hasKey(std::string const& attribute) const {
bool hasKey(StringRef const& attribute) const {
return !get(attribute).isNone();
}
bool hasKey(std::string const& attribute) const {
return hasKey(StringRef(attribute));
}
bool hasKey(char const* attribute) const {
return hasKey(StringRef(attribute));
}
bool hasKey(char const* attribute, size_t length) const {
return hasKey(StringRef(attribute, length));
}
// whether or not an Object has a specific sub-key
bool hasKey(std::vector<std::string> const& attributes) const {
return !get(attributes).isNone();
@ -706,6 +694,25 @@ class Slice {
throw Exception(Exception::InvalidValueType, "Expecting type String");
}
// return a copy of the value for a String object
StringRef stringRef() const {
uint8_t h = head();
if (h >= 0x40 && h <= 0xbe) {
// short UTF-8 String
ValueLength length = h - 0x40;
return StringRef(reinterpret_cast<char const*>(_start + 1),
static_cast<size_t>(length));
}
if (h == 0xbf) {
ValueLength length = readIntegerFixed<ValueLength, 8>(_start + 1);
return StringRef(reinterpret_cast<char const*>(_start + 1 + 8),
checkOverflow(length));
}
throw Exception(Exception::InvalidValueType, "Expecting type String");
}
// return the value for a Binary object
uint8_t const* getBinary(ValueLength& length) const {
if (!isBinary()) {
@ -879,15 +886,37 @@ class Slice {
Slice makeKey() const;
int compareString(char const* value, size_t length) const;
int compareStringUnchecked(char const* value, size_t length) const noexcept;
int compareString(StringRef const& value) const;
inline int compareString(std::string const& attribute) const {
return compareString(attribute.data(), attribute.size());
inline int compareString(std::string const& value) const {
return compareString(StringRef(value.data(), value.size()));
}
bool isEqualString(std::string const& attribute) const;
bool isEqualStringUnchecked(std::string const& attribute) const noexcept;
int compareString(char const* value, size_t length) const {
return compareString(StringRef(value, length));
}
int compareStringUnchecked(StringRef const& value) const noexcept;
int compareStringUnchecked(std::string const& value) const noexcept {
return compareStringUnchecked(StringRef(value.data(), value.size()));
}
int compareStringUnchecked(char const* value, size_t length) const noexcept {
return compareStringUnchecked(StringRef(value, length));
}
bool isEqualString(StringRef const& attribute) const;
bool isEqualString(std::string const& attribute) const {
return isEqualString(StringRef(attribute.data(), attribute.size()));
}
bool isEqualStringUnchecked(StringRef const& attribute) const noexcept;
bool isEqualStringUnchecked(std::string const& attribute) const noexcept {
return isEqualStringUnchecked(StringRef(attribute.data(), attribute.size()));
}
// check if two Slices are equal on the binary level
bool equals(Slice const& other) const {
@ -944,7 +973,7 @@ class Slice {
// translates an integer key into a string, without checks
Slice translateUnchecked() const;
Slice getFromCompactObject(std::string const& attribute) const;
Slice getFromCompactObject(StringRef const& attribute) const;
// extract the nth member from an Array
Slice getNth(ValueLength index) const;
@ -968,12 +997,12 @@ class Slice {
}
// perform a linear search for the specified attribute inside an Object
Slice searchObjectKeyLinear(std::string const& attribute, ValueLength ieBase,
Slice searchObjectKeyLinear(StringRef const& attribute, ValueLength ieBase,
ValueLength offsetSize, ValueLength n) const;
// perform a binary search for the specified attribute inside an Object
template<ValueLength offsetSize>
Slice searchObjectKeyBinary(std::string const& attribute, ValueLength ieBase, ValueLength n) const;
Slice searchObjectKeyBinary(StringRef const& attribute, ValueLength ieBase, ValueLength n) const;
// assert that the slice is of a specific type
// can be used for debugging and removed in production

View File

@ -29,12 +29,14 @@
#include <cstdint>
#include <cstring>
#include <algorithm>
#include <string>
#include "velocypack/velocypack-common.h"
#include "velocypack/Slice.h"
namespace arangodb {
namespace velocypack {
class Slice;
class StringRef {
public:
@ -44,19 +46,18 @@ class StringRef {
/// @brief create a StringRef from an std::string
explicit StringRef(std::string const& str) noexcept : StringRef(str.data(), str.size()) {}
/// @brief create a StringRef from a C string plus length
constexpr StringRef(char const* data, size_t length) noexcept : _data(data), _length(length) {}
/// @brief create a StringRef from a null-terminated C string
#if __cplusplus >= 201703
constexpr explicit StringRef(char const* data) noexcept : StringRef(data, std::char_traits<char>::length(data)) {}
#else
explicit StringRef(char const* data) noexcept : StringRef(data, strlen(data)) {}
#endif
/// @brief create a StringRef from a VPack slice (must be of type String)
explicit StringRef(arangodb::velocypack::Slice const& slice) {
VELOCYPACK_ASSERT(slice.isString());
arangodb::velocypack::ValueLength l;
_data = slice.getString(l);
_length = l;
}
/// @brief create a StringRef from a C string plus length
StringRef(char const* data, size_t length) noexcept : _data(data), _length(length) {}
explicit StringRef(arangodb::velocypack::Slice const& slice);
/// @brief create a StringRef from another StringRef
StringRef(StringRef const& other) noexcept
@ -95,12 +96,7 @@ class StringRef {
}
/// @brief create a StringRef from a VPack slice of type String
StringRef& operator=(arangodb::velocypack::Slice const& slice) {
arangodb::velocypack::ValueLength l;
_data = slice.getString(l);
_length = l;
return *this;
}
StringRef& operator=(arangodb::velocypack::Slice const& slice);
int compare(std::string const& other) const noexcept {
int res = memcmp(_data, other.data(), (std::min)(_length, other.size()));
@ -126,17 +122,17 @@ class StringRef {
return (_length == 0);
}
inline char const* begin() const {
inline char const* begin() const noexcept {
return _data;
}
inline char const* end() const {
inline char const* end() const noexcept {
return _data + _length;
}
inline char front() const { return _data[0]; }
inline char front() const noexcept { return _data[0]; }
inline char back() const { return _data[_length - 1]; }
inline char back() const noexcept { return _data[_length - 1]; }
inline char operator[](size_t index) const noexcept {
return _data[index];

View File

@ -30,6 +30,7 @@
#include <cstdint>
// for size_t:
#include <cstring>
#include <type_traits>
#if defined(__GNUC__) || defined(__GNUG__)
#define VELOCYPACK_LIKELY(v) __builtin_expect(!!(v), 1)
@ -77,6 +78,26 @@
#define VELOCYPACK_UNUSED /* unused */
#endif
#ifndef VELOCYPACK_XXHASH
#ifndef VELOCYPACK_FASTHASH
#define VELOCYPACK_XXHASH
#endif
#endif
#ifdef VELOCYPACK_XXHASH
// forward for XXH64 function declared elsewhere
extern "C" unsigned long long XXH64(void const*, size_t, unsigned long long);
#define VELOCYPACK_HASH(mem, size, seed) XXH64(mem, size, seed)
#endif
#ifdef VELOCYPACK_FASTHASH
// forward for fasthash64 function declared elsewhere
uint64_t fasthash64(void const*, size_t, uint64_t);
#define VELOCYPACK_HASH(mem, size, seed) fasthash64(mem, size, seed)
#endif
namespace arangodb {
namespace velocypack {
@ -177,10 +198,12 @@ static inline int64_t toInt64(uint64_t v) noexcept {
// specified length, starting at the specified byte offset
template <typename T, ValueLength length>
static inline T readIntegerFixed(uint8_t const* start) noexcept {
static_assert(std::is_unsigned<T>::value, "result type must be unsigned");
static_assert(length > 0, "length must be > 0");
static_assert(length <= sizeof(T), "length must be <= sizeof(T)");
uint64_t x = 8;
uint8_t const* end = start + length;
uint64_t value = static_cast<T>(*start++);
T value = static_cast<T>(*start++);
while (start < end) {
value += static_cast<T>(*start++) << x;
x += 8;
@ -189,13 +212,15 @@ static inline T readIntegerFixed(uint8_t const* start) noexcept {
}
// read an unsigned little endian integer value of the
// specified length, starting at the specified byte offset
// specified, non-0 length, starting at the specified byte offset
template <typename T>
static inline T readIntegerNonEmpty(uint8_t const* start, ValueLength length) noexcept {
static_assert(std::is_unsigned<T>::value, "result type must be unsigned");
VELOCYPACK_ASSERT(length > 0);
VELOCYPACK_ASSERT(length <= sizeof(T));
uint64_t x = 8;
uint8_t const* end = start + length;
uint64_t value = static_cast<T>(*start++);
T value = static_cast<T>(*start++);
while (start < end) {
value += static_cast<T>(*start++) << x;
x += 8;

View File

@ -35,40 +35,12 @@
using namespace arangodb::velocypack;
std::string Builder::toString() const {
Options options;
options.prettyPrint = true;
std::string buffer;
StringSink sink(&buffer);
Dumper::dump(slice(), &sink, &options);
return buffer;
}
std::string Builder::toJson() const {
std::string buffer;
StringSink sink(&buffer);
Dumper::dump(slice(), &sink);
return buffer;
}
void Builder::doActualSort(std::vector<SortEntry>& entries) {
VELOCYPACK_ASSERT(entries.size() > 1);
std::sort(entries.begin(), entries.end(),
[](SortEntry const& a, SortEntry const& b) {
// return true iff a < b:
uint8_t const* pa = a.nameStart;
uint64_t sizea = a.nameSize;
uint8_t const* pb = b.nameStart;
uint64_t sizeb = b.nameSize;
size_t const compareLength = checkOverflow((std::min)(sizea, sizeb));
int res = memcmp(pa, pb, compareLength);
return (res < 0 || (res == 0 && sizea < sizeb));
});
};
uint8_t const* Builder::findAttrName(uint8_t const* base, uint64_t& len) {
namespace {
// Find the actual bytes of the attribute name of the VPack value
// at position base, also determine the length len of the attribute.
// This takes into account the different possibilities for the format
// of attribute names:
static uint8_t const* findAttrName(uint8_t const* base, uint64_t& len) {
uint8_t const b = *base;
if (b >= 0x40 && b <= 0xbe) {
// short UTF-8 string
@ -86,18 +58,20 @@ uint8_t const* Builder::findAttrName(uint8_t const* base, uint64_t& len) {
}
// translate attribute name
return findAttrName(Slice(base).makeKey().start(), len);
return findAttrName(arangodb::velocypack::Slice(base).makeKey().start(), len);
}
void Builder::sortObjectIndexShort(uint8_t* objBase,
std::vector<ValueLength>& offsets) const {
std::sort(offsets.begin(), offsets.end(), [&objBase](ValueLength a, ValueLength b) -> bool {
struct ObjectIndexSorterShort {
explicit ObjectIndexSorterShort(uint8_t const* objBase) : objBase(objBase) {}
bool operator()(arangodb::velocypack::ValueLength const& a,
arangodb::velocypack::ValueLength const& b) const noexcept {
uint8_t const* aa = objBase + a;
uint8_t const* bb = objBase + b;
if (*aa >= 0x40 && *aa <= 0xbe && *bb >= 0x40 && *bb <= 0xbe) {
// The fast path, short strings:
uint8_t m = (std::min)(*aa - 0x40, *bb - 0x40);
int c = memcmp(aa + 1, bb + 1, checkOverflow(m));
int c = memcmp(aa + 1, bb + 1, arangodb::velocypack::checkOverflow(m));
return (c < 0 || (c == 0 && *aa < *bb));
} else {
uint64_t lena;
@ -105,10 +79,52 @@ void Builder::sortObjectIndexShort(uint8_t* objBase,
aa = findAttrName(aa, lena);
bb = findAttrName(bb, lenb);
uint64_t m = (std::min)(lena, lenb);
int c = memcmp(aa, bb, checkOverflow(m));
int c = memcmp(aa, bb, arangodb::velocypack::checkOverflow(m));
return (c < 0 || (c == 0 && lena < lenb));
}
});
}
uint8_t const* objBase;
};
struct ObjectIndexSorterLong {
bool operator()(arangodb::velocypack::Builder::SortEntry const& a,
arangodb::velocypack::Builder::SortEntry const& b) const noexcept {
// return true iff a < b:
uint8_t const* pa = a.nameStart;
uint64_t sizea = a.nameSize;
uint8_t const* pb = b.nameStart;
uint64_t sizeb = b.nameSize;
size_t const compareLength = arangodb::velocypack::checkOverflow((std::min)(sizea, sizeb));
int res = memcmp(pa, pb, compareLength);
return (res < 0 || (res == 0 && sizea < sizeb));
}
};
} // namespace
std::string Builder::toString() const {
Options options;
options.prettyPrint = true;
std::string buffer;
StringSink sink(&buffer);
Dumper::dump(slice(), &sink, &options);
return buffer;
}
std::string Builder::toJson() const {
std::string buffer;
StringSink sink(&buffer);
Dumper::dump(slice(), &sink);
return buffer;
}
void Builder::sortObjectIndexShort(uint8_t* objBase,
std::vector<ValueLength>& offsets) const {
std::sort(offsets.begin(), offsets.end(), ::ObjectIndexSorterShort(objBase));
}
void Builder::sortObjectIndexLong(uint8_t* objBase,
@ -116,15 +132,16 @@ void Builder::sortObjectIndexLong(uint8_t* objBase,
_sortEntries.clear();
size_t const n = offsets.size();
VELOCYPACK_ASSERT(n > 1);
_sortEntries.reserve(n);
for (size_t i = 0; i < n; i++) {
SortEntry e;
e.offset = offsets[i];
e.nameStart = findAttrName(objBase + e.offset, e.nameSize);
e.nameStart = ::findAttrName(objBase + e.offset, e.nameSize);
_sortEntries.push_back(e);
}
VELOCYPACK_ASSERT(_sortEntries.size() == n);
doActualSort(_sortEntries);
std::sort(_sortEntries.begin(), _sortEntries.end(), ::ObjectIndexSorterLong());
// copy back the sorted offsets
for (size_t i = 0; i < n; i++) {
@ -133,15 +150,6 @@ void Builder::sortObjectIndexLong(uint8_t* objBase,
_sortEntries.clear();
}
void Builder::sortObjectIndex(uint8_t* objBase,
std::vector<ValueLength>& offsets) {
if (offsets.size() > 32) {
sortObjectIndexLong(objBase, offsets);
} else {
sortObjectIndexShort(objBase, offsets);
}
}
void Builder::removeLast() {
if (_stack.empty()) {
throw Exception(Exception::BuilderNeedOpenCompound);

View File

@ -746,7 +746,7 @@ uint64_t Slice::normalizedHash(uint64_t seed) const {
// look for the specified attribute inside an Object
// returns a Slice(ValueType::None) if not found
Slice Slice::get(std::string const& attribute) const {
Slice Slice::get(StringRef const& attribute) const {
if (VELOCYPACK_UNLIKELY(!isObject())) {
throw Exception(Exception::InvalidValueType, "Expecting Object");
}
@ -934,12 +934,13 @@ int64_t Slice::getSmallInt() const {
throw Exception(Exception::InvalidValueType, "Expecting type SmallInt");
}
int Slice::compareString(char const* value, size_t length) const {
int Slice::compareString(StringRef const& value) const {
size_t const length = value.size();
ValueLength keyLength;
char const* k = getString(keyLength);
size_t const compareLength =
(std::min)(static_cast<size_t>(keyLength), length);
int res = memcmp(k, value, compareLength);
int res = memcmp(k, value.data(), compareLength);
if (res == 0) {
if (keyLength != length) {
@ -949,12 +950,13 @@ int Slice::compareString(char const* value, size_t length) const {
return res;
}
int Slice::compareStringUnchecked(char const* value, size_t length) const noexcept {
int Slice::compareStringUnchecked(StringRef const& value) const noexcept {
size_t const length = value.size();
ValueLength keyLength;
char const* k = getStringUnchecked(keyLength);
size_t const compareLength =
(std::min)(static_cast<size_t>(keyLength), length);
int res = memcmp(k, value, compareLength);
int res = memcmp(k, value.data(), compareLength);
if (res == 0) {
if (keyLength != length) {
@ -964,7 +966,7 @@ int Slice::compareStringUnchecked(char const* value, size_t length) const noexce
return res;
}
bool Slice::isEqualString(std::string const& attribute) const {
bool Slice::isEqualString(StringRef const& attribute) const {
ValueLength keyLength;
char const* k = getString(keyLength);
if (static_cast<size_t>(keyLength) != attribute.size()) {
@ -973,7 +975,7 @@ bool Slice::isEqualString(std::string const& attribute) const {
return (memcmp(k, attribute.data(), attribute.size()) == 0);
}
bool Slice::isEqualStringUnchecked(std::string const& attribute) const noexcept {
bool Slice::isEqualStringUnchecked(StringRef const& attribute) const noexcept {
ValueLength keyLength;
char const* k = getStringUnchecked(keyLength);
if (static_cast<size_t>(keyLength) != attribute.size()) {
@ -982,7 +984,7 @@ bool Slice::isEqualStringUnchecked(std::string const& attribute) const noexcept
return (memcmp(k, attribute.data(), attribute.size()) == 0);
}
Slice Slice::getFromCompactObject(std::string const& attribute) const {
Slice Slice::getFromCompactObject(StringRef const& attribute) const {
ObjectIterator it(*this);
while (it.valid()) {
Slice key = it.key(false);
@ -1116,7 +1118,7 @@ ValueLength Slice::getNthOffsetFromCompact(ValueLength index) const {
}
// perform a linear search for the specified attribute inside an Object
Slice Slice::searchObjectKeyLinear(std::string const& attribute,
Slice Slice::searchObjectKeyLinear(StringRef const& attribute,
ValueLength ieBase, ValueLength offsetSize,
ValueLength n) const {
bool const useTranslator = (Options::Defaults.attributeTranslator != nullptr);
@ -1153,7 +1155,7 @@ Slice Slice::searchObjectKeyLinear(std::string const& attribute,
// perform a binary search for the specified attribute inside an Object
template<ValueLength offsetSize>
Slice Slice::searchObjectKeyBinary(std::string const& attribute,
Slice Slice::searchObjectKeyBinary(StringRef const& attribute,
ValueLength ieBase,
ValueLength n) const {
bool const useTranslator = (Options::Defaults.attributeTranslator != nullptr);
@ -1205,10 +1207,10 @@ Slice Slice::searchObjectKeyBinary(std::string const& attribute,
}
// template instanciations for searchObjectKeyBinary
template Slice Slice::searchObjectKeyBinary<1>(std::string const& attribute, ValueLength ieBase, ValueLength n) const;
template Slice Slice::searchObjectKeyBinary<2>(std::string const& attribute, ValueLength ieBase, ValueLength n) const;
template Slice Slice::searchObjectKeyBinary<4>(std::string const& attribute, ValueLength ieBase, ValueLength n) const;
template Slice Slice::searchObjectKeyBinary<8>(std::string const& attribute, ValueLength ieBase, ValueLength n) const;
template Slice Slice::searchObjectKeyBinary<1>(StringRef const& attribute, ValueLength ieBase, ValueLength n) const;
template Slice Slice::searchObjectKeyBinary<2>(StringRef const& attribute, ValueLength ieBase, ValueLength n) const;
template Slice Slice::searchObjectKeyBinary<4>(StringRef const& attribute, ValueLength ieBase, ValueLength n) const;
template Slice Slice::searchObjectKeyBinary<8>(StringRef const& attribute, ValueLength ieBase, ValueLength n) const;
SliceScope::SliceScope() : _allocations() {}

45
3rdParty/velocypack/src/StringRef.cpp vendored Normal file
View File

@ -0,0 +1,45 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief Library to build up VPack documents.
///
/// DISCLAIMER
///
/// Copyright 2015 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Jan Steemann
/// @author Copyright 2015, ArangoDB GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "velocypack/StringRef.h"
#include "velocypack/Slice.h"
using namespace arangodb::velocypack;
StringRef::StringRef(arangodb::velocypack::Slice const& slice) {
VELOCYPACK_ASSERT(slice.isString());
arangodb::velocypack::ValueLength l;
_data = slice.getString(l);
_length = l;
}
/// @brief create a StringRef from a VPack slice of type String
StringRef& StringRef::operator=(arangodb::velocypack::Slice const& slice) {
arangodb::velocypack::ValueLength l;
_data = slice.getString(l);
_length = l;
return *this;
}

View File

@ -274,7 +274,7 @@ std::string ActiveFailoverJob::findBestFollower() {
if (!resp.isArray() || resp.length() == 0) {
return "";
}
VPackSlice obj = resp.at(0).get({ Job::agencyPrefix, "AsyncReplication"});
VPackSlice obj = resp.at(0).get<std::string>({ Job::agencyPrefix, std::string("AsyncReplication") });
for (VPackObjectIterator::ObjectPair pair : VPackObjectIterator(obj)) {
std::string srvUUID = pair.key.copyString();
bool isAvailable = std::find(healthy.begin(), healthy.end(), srvUUID) != healthy.end();

View File

@ -124,6 +124,14 @@ struct AqlValueHintUInt {
uint64_t const value;
};
struct AqlValueHintEmptyArray {
constexpr AqlValueHintEmptyArray() noexcept {}
};
struct AqlValueHintEmptyObject {
constexpr AqlValueHintEmptyObject() noexcept {}
};
struct AqlValue final {
friend struct std::hash<arangodb::aql::AqlValue>;
friend struct std::equal_to<arangodb::aql::AqlValue>;
@ -330,6 +338,16 @@ struct AqlValue final {
// construct from std::string
explicit AqlValue(std::string const& value) : AqlValue(value.c_str(), value.size()) {}
explicit AqlValue(AqlValueHintEmptyArray const&) noexcept {
_data.internal[0] = 0x01; // empty array in VPack
setType(AqlValueType::VPACK_INLINE);
}
explicit AqlValue(AqlValueHintEmptyObject const&) noexcept {
_data.internal[0] = 0x0a; // empty object in VPack
setType(AqlValueType::VPACK_INLINE);
}
// construct from Buffer, potentially taking over its ownership
// (by adjusting the boolean passed)
AqlValue(arangodb::velocypack::Buffer<uint8_t>* buffer, bool& shouldDelete) {

View File

@ -588,7 +588,7 @@ AqlValue Expression::executeSimpleExpressionArray(
size_t const n = node->numMembers();
if (n == 0) {
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
transaction::BuilderLeaser builder(trx);
@ -621,7 +621,7 @@ AqlValue Expression::executeSimpleExpressionObject(
size_t const n = node->numMembers();
if (n == 0) {
return AqlValue(arangodb::velocypack::Slice::emptyObjectSlice());
return AqlValue(AqlValueHintEmptyObject());
}
// unordered map to make object keys unique afterwards
@ -1398,7 +1398,7 @@ AqlValue Expression::executeSimpleExpressionExpansion(
if (offset < 0 || count <= 0) {
// no items to return... can already stop here
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
// FILTER
@ -1412,7 +1412,7 @@ AqlValue Expression::executeSimpleExpressionExpansion(
filterNode = nullptr;
} else {
// filter expression is always false
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
}
@ -1431,7 +1431,7 @@ AqlValue Expression::executeSimpleExpressionExpansion(
if (!a.isArray()) {
TRI_ASSERT(!mustDestroy);
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
VPackBuilder builder;
@ -1473,7 +1473,7 @@ AqlValue Expression::executeSimpleExpressionExpansion(
if (!a.isArray()) {
TRI_ASSERT(!mustDestroy);
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
mustDestroy = localMustDestroy; // maybe we need to destroy...

View File

@ -1207,7 +1207,7 @@ AqlValue mergeParameters(ExpressionContext* expressionContext,
size_t const n = parameters.size();
if (n == 0) {
return AqlValue(arangodb::velocypack::Slice::emptyObjectSlice());
return AqlValue(AqlValueHintEmptyObject());
}
// use the first argument as the preliminary result
@ -1749,7 +1749,7 @@ AqlValue Functions::ToArray(ExpressionContext*,
}
if (value.isNull(true)) {
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
transaction::BuilderLeaser builder(trx);
@ -2915,7 +2915,7 @@ AqlValue Functions::Split(ExpressionContext* expressionContext,
return AqlValue(AqlValueHintNull());
}
if (limitNumber == 0) {
return AqlValue(VPackSlice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
}
@ -3119,7 +3119,7 @@ AqlValue Functions::RegexSplit(ExpressionContext* expressionContext,
return AqlValue(AqlValueHintNull());
}
if (limitNumber == 0) {
return AqlValue(VPackSlice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
}
@ -4109,7 +4109,7 @@ AqlValue Functions::Attributes(ExpressionContext* expressionContext,
TRI_ASSERT(value.isObject());
if (value.length() == 0) {
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
AqlValueMaterializer materializer(trx);
@ -4173,7 +4173,7 @@ AqlValue Functions::Values(ExpressionContext* expressionContext,
TRI_ASSERT(value.isObject());
if (value.length() == 0) {
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
AqlValueMaterializer materializer(trx);
@ -6426,7 +6426,7 @@ AqlValue Functions::RemoveValue(ExpressionContext* expressionContext,
AqlValue list = ExtractFunctionParameterValue(parameters, 0);
if (list.isNull(true)) {
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
if (!list.isArray()) {
@ -6487,7 +6487,7 @@ AqlValue Functions::RemoveValues(ExpressionContext* expressionContext,
}
if (list.isNull(true)) {
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
if (!list.isArray() || !values.isArray()) {
@ -6522,7 +6522,7 @@ AqlValue Functions::RemoveNth(ExpressionContext* expressionContext,
AqlValue list = ExtractFunctionParameterValue(parameters, 0);
if (list.isNull(true)) {
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
if (!list.isArray()) {
@ -7061,7 +7061,7 @@ AqlValue Functions::PregelResult(ExpressionContext* expressionContext,
pregel::PregelFeature* feature = pregel::PregelFeature::instance();
if (!feature) {
::registerWarning(expressionContext, AFN, TRI_ERROR_FAILED);
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
auto buffer = std::make_unique<VPackBuffer<uint8_t>>();
@ -7070,7 +7070,7 @@ AqlValue Functions::PregelResult(ExpressionContext* expressionContext,
std::shared_ptr<pregel::Conductor> c = feature->conductor(execNr);
if (!c) {
::registerWarning(expressionContext, AFN, TRI_ERROR_HTTP_NOT_FOUND);
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
c->collectAQLResults(builder);
@ -7078,13 +7078,13 @@ AqlValue Functions::PregelResult(ExpressionContext* expressionContext,
std::shared_ptr<pregel::IWorker> worker = feature->worker(execNr);
if (!worker) {
::registerWarning(expressionContext, AFN, TRI_ERROR_HTTP_NOT_FOUND);
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
worker->aqlResult(builder);
}
if (builder.isEmpty()) {
return AqlValue(arangodb::velocypack::Slice::emptyArraySlice());
return AqlValue(AqlValueHintEmptyArray());
}
TRI_ASSERT(builder.slice().isArray());

View File

@ -2232,7 +2232,7 @@ Result ClusterInfo::setViewPropertiesCoordinator(
return { TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND };
}
auto const view = res.slice()[0].get(
auto const view = res.slice()[0].get<std::string>(
{ AgencyCommManager::path(), "Plan", "Views", databaseName, viewID }
);

View File

@ -602,14 +602,14 @@ void HeartbeatThread::runSingleServer() {
VPackSlice agentPool = response.get(".agency");
updateAgentPool(agentPool);
VPackSlice shutdownSlice = response.get({AgencyCommManager::path(), "Shutdown"});
VPackSlice shutdownSlice = response.get<std::string>({AgencyCommManager::path(), "Shutdown"});
if (shutdownSlice.isBool() && shutdownSlice.getBool()) {
ApplicationServer::server->beginShutdown();
break;
}
// performing failover checks
VPackSlice async = response.get({AgencyCommManager::path(), "Plan", "AsyncReplication"});
VPackSlice async = response.get<std::string>({AgencyCommManager::path(), "Plan", "AsyncReplication"});
if (!async.isObject()) {
LOG_TOPIC(WARN, Logger::HEARTBEAT)
<< "Heartbeat: Could not read async-replication metadata from agency!";

View File

@ -91,7 +91,7 @@ arangodb::Result Databases::info(TRI_vocbase_t* vocbase, VPackBuilder& result) {
return Result(commRes.errorCode(), commRes.errorMessage());
}
VPackSlice value = commRes.slice()[0].get(
VPackSlice value = commRes.slice()[0].get<std::string>(
{AgencyCommManager::path(), "Plan", "Databases", vocbase->name()});
if (value.isObject() && value.hasKey("name")) {
VPackValueLength l = 0;

View File

@ -102,7 +102,7 @@ void* LanguageFeature::prepareIcu(std::string const& binaryPath,
"'; please make sure it is available; "
"the variable ICU_DATA='";
std::string icupath;
if ( TRI_GETENV("ICU_DATA", icupath)) {
if (TRI_GETENV("ICU_DATA", icupath)) {
msg += icupath;
}
msg += "' should point to the directory containing '" + fn + "'";

View File

@ -42,7 +42,7 @@ class StringRef {
constexpr StringRef() : _data(""), _length(0) {}
/// @brief create a StringRef from an std::string
explicit StringRef(std::string const& str) : _data(str.c_str()), _length(str.size()) {}
explicit StringRef(std::string const& str) noexcept : _data(str.data()), _length(str.size()) {}
/// @brief create a StringRef from a null-terminated C string
explicit StringRef(char const* data) : _data(data), _length(strlen(data)) {}

View File

@ -75,6 +75,7 @@ set(LIB_ARANGO_VPACK
${PROJECT_SOURCE_DIR}/3rdParty/velocypack/src/Options.cpp
${PROJECT_SOURCE_DIR}/3rdParty/velocypack/src/Parser.cpp
${PROJECT_SOURCE_DIR}/3rdParty/velocypack/src/Slice.cpp
${PROJECT_SOURCE_DIR}/3rdParty/velocypack/src/StringRef.cpp
${PROJECT_SOURCE_DIR}/3rdParty/velocypack/src/Utf8Helper.cpp
${PROJECT_SOURCE_DIR}/3rdParty/velocypack/src/ValueType.cpp
${PROJECT_SOURCE_DIR}/3rdParty/velocypack/src/Validator.cpp

View File

@ -261,7 +261,7 @@ std::unique_ptr<arangodb::aql::ExecutionPlan> planFromQuery(
uint64_t getCurrentPlanVersion() {
auto const result = arangodb::AgencyComm().getValues("Plan");
auto const planVersionSlice = result.slice()[0].get(
auto const planVersionSlice = result.slice()[0].get<std::string>(
{ arangodb::AgencyCommManager::path(), "Plan", "Version" }
);
return planVersionSlice.getNumber<uint64_t>();