From dca8efa82f6f7fc08e630ce0e4e7de2989f20c41 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Fri, 13 Nov 2015 12:58:17 +0100 Subject: [PATCH] updated vpack library --- .../velocypack/include/velocypack/Builder.h | 113 ++++-- .../velocypack/include/velocypack/Dumper.h | 27 +- .../velocypack/include/velocypack/Iterator.h | 107 ++++- .../velocypack/include/velocypack/Options.h | 10 +- .../velocypack/include/velocypack/Parser.h | 41 +- 3rdParty/velocypack/include/velocypack/Sink.h | 94 +++-- .../velocypack/include/velocypack/Slice.h | 375 ++++------------- .../velocypack/include/velocypack/Value.h | 46 ++- .../include/velocypack/velocypack-aliases.h | 1 + .../include/velocypack/velocypack-common.h | 64 ++- 3rdParty/velocypack/src/Builder.cpp | 88 +++- 3rdParty/velocypack/src/Dumper.cpp | 49 ++- 3rdParty/velocypack/src/Parser.cpp | 14 +- 3rdParty/velocypack/src/Slice.cpp | 384 +++++++++++++++++- 3rdParty/velocypack/src/asm-functions.cpp | 27 +- 3rdParty/velocypack/src/velocypack-common.cpp | 4 +- lib/Basics/VelocyPackHelper.cpp | 5 +- lib/Rest/HttpRequest.cpp | 8 +- 18 files changed, 940 insertions(+), 517 deletions(-) diff --git a/3rdParty/velocypack/include/velocypack/Builder.h b/3rdParty/velocypack/include/velocypack/Builder.h index 13f96f6ce3..bdf7eb457c 100644 --- a/3rdParty/velocypack/include/velocypack/Builder.h +++ b/3rdParty/velocypack/include/velocypack/Builder.h @@ -27,11 +27,11 @@ #ifndef VELOCYPACK_BUILDER_H #define VELOCYPACK_BUILDER_H -#include #include #include #include #include +#include #include "velocypack/velocypack-common.h" #include "velocypack/Buffer.h" @@ -62,7 +62,7 @@ namespace arangodb { private: - Buffer _buffer; // Here we collect the result + std::shared_ptr> _buffer; // Here we collect the result uint8_t* _start; // Always points to the start of _buffer ValueLength _size; // Always contains the size of _buffer ValueLength _pos; // the append position, always <= _size @@ -99,11 +99,11 @@ namespace arangodb { if (_pos + len <= _size) { return; // All OK, we can just increase tos->pos by len } - CheckValueLength(_pos + len); + checkValueLength(_pos + len); - _buffer.prealloc(len); - _start = _buffer.data(); - _size = _buffer.size(); + _buffer->prealloc(len); + _start = _buffer->data(); + _size = _buffer->size(); } // Sort the indices by attribute name: @@ -126,16 +126,33 @@ namespace arangodb { public: - Options options; + Options const* options; // Constructor and destructor: - - Builder (Options const& options = Options::Defaults) - : _buffer({ 0 }), + Builder (std::shared_ptr>& buffer, Options const* options = &Options::Defaults) + : _buffer(buffer), _pos(0), options(options) { - _start = _buffer.data(); - _size = _buffer.size(); + _start = _buffer->data(); + _size = _buffer->size(); + + VELOCYPACK_ASSERT(options != nullptr); + if (options == nullptr) { + throw Exception(Exception::InternalError, "Options cannot be a nullptr"); + } + } + + Builder (Options const* options = &Options::Defaults) + : _buffer(new Buffer()), + _pos(0), + options(options) { + _start = _buffer->data(); + _size = _buffer->size(); + + VELOCYPACK_ASSERT(options != nullptr); + if (options == nullptr) { + throw Exception(Exception::InternalError, "Options cannot be a nullptr"); + } } // The rule of five: @@ -144,61 +161,89 @@ namespace arangodb { } Builder (Builder const& that) - : _buffer(that._buffer), _start(_buffer.data()), _size(_buffer.size()), _pos(that._pos), + : _buffer(that._buffer), _start(_buffer->data()), _size(_buffer->size()), _pos(that._pos), _stack(that._stack), _index(that._index), options(that.options) { + VELOCYPACK_ASSERT(options != nullptr); + if (that._buffer == nullptr) { + throw Exception(Exception::InternalError, "Buffer of Builder is already gone"); + } } Builder& operator= (Builder const& that) { + if (that._buffer == nullptr) { + throw Exception(Exception::InternalError, "Buffer of Builder is already gone"); + } _buffer = that._buffer; - _start = _buffer.data(); - _size = _buffer.size(); + _start = _buffer->data(); + _size = _buffer->size(); _pos = that._pos; _stack = that._stack; _index = that._index; options = that.options; + VELOCYPACK_ASSERT(options != nullptr); return *this; } Builder (Builder&& that) { - _buffer.reset(); + if (that._buffer == nullptr) { + throw Exception(Exception::InternalError, "Buffer of Builder is already gone"); + } _buffer = that._buffer; that._buffer.reset(); - _start = _buffer.data(); - _size = _buffer.size(); + _start = _buffer->data(); + _size = _buffer->size(); _pos = that._pos; _stack.clear(); _stack.swap(that._stack); _index.clear(); _index.swap(that._index); options = that.options; + VELOCYPACK_ASSERT(options != nullptr); that._start = nullptr; that._size = 0; that._pos = 0; } Builder& operator= (Builder&& that) { - _buffer.reset(); + if (that._buffer == nullptr) { + throw Exception(Exception::InternalError, "Buffer of Builder is already gone"); + } _buffer = that._buffer; that._buffer.reset(); - _start = _buffer.data(); - _size = _buffer.size(); + _start = _buffer->data(); + _size = _buffer->size(); _pos = that._pos; _stack.clear(); _stack.swap(that._stack); _index.clear(); _index.swap(that._index); options = that.options; + VELOCYPACK_ASSERT(options != nullptr); that._start = nullptr; that._size = 0; that._pos = 0; return *this; } - static Builder clone (Slice const& slice, Options const& options = Options::Defaults) { + // get a const reference to the Builder's Buffer object + std::shared_ptr> const& buffer () const { + return _buffer; + } + + // get a non-const reference to the Builder's Buffer object + std::shared_ptr>& buffer () { + return _buffer; + } + + static Builder clone (Slice const& slice, Options const* options = &Options::Defaults) { + VELOCYPACK_ASSERT(options != nullptr); + if (options == nullptr) { + throw Exception(Exception::InternalError, "Options cannot be a nullptr"); + } Builder b; b.options = options; b.add(slice); - return b; + return std::move(b); } // Clear and start from scratch: @@ -217,7 +262,7 @@ namespace arangodb { // Return a Slice of the result: Slice slice () const { - return Slice(start(), options.customTypeHandler); + return Slice(start(), options); } // Compute the actual size here, but only when sealed @@ -343,7 +388,7 @@ namespace arangodb { void addUTCDate (int64_t v) { uint8_t vSize = sizeof(int64_t); // is always 8 - uint64_t x = ToUInt64(v); + uint64_t x = toUInt64(v); reserveSpace(1 + vSize); _start[_pos++] = 0x1c; appendLength(x, 8); @@ -366,12 +411,12 @@ namespace arangodb { return target; } - void addArray () { - addCompoundValue(0x06); + inline void addArray (bool unindexed = false) { + addCompoundValue(unindexed ? 0x13 : 0x06); } - void addObject () { - addCompoundValue(0x0b); + inline void addObject (bool unindexed = false) { + addCompoundValue(unindexed ? 0x14 : 0x0b); } private: @@ -380,7 +425,7 @@ namespace arangodb { uint8_t* addInternal (T const& sub) { if (! _stack.empty()) { ValueLength& tos = _stack.back(); - if (_start[tos] != 0x06) { + if (_start[tos] != 0x06 && _start[tos] != 0x13) { throw Exception(Exception::BuilderNeedOpenArray); } reportAdd(tos); @@ -392,7 +437,7 @@ namespace arangodb { uint8_t* addInternal (std::string const& attrName, T const& sub) { if (! _stack.empty()) { ValueLength& tos = _stack.back(); - if (_start[tos] != 0x0b) { + if (_start[tos] != 0x0b && _start[tos] != 0x14) { throw Exception(Exception::BuilderNeedOpenObject); } reportAdd(tos); @@ -403,7 +448,7 @@ namespace arangodb { void addCompoundValue (uint8_t type) { reserveSpace(9); - // an array is started: + // an Array or Object is started: _stack.push_back(_pos); while (_stack.size() > _index.size()) { _index.emplace_back(); @@ -466,7 +511,7 @@ namespace arangodb { uint8_t vSize = intLength(v); uint64_t x; if (vSize == 8) { - x = ToUInt64(v); + x = toUInt64(v); } else { int64_t shift = 1LL << (vSize * 8 - 1); // will never overflow! @@ -481,7 +526,7 @@ namespace arangodb { } } - void checkAttributeUniqueness (Slice const obj) const; + void checkAttributeUniqueness (Slice const& obj) const; }; } // namespace arangodb::velocypack diff --git a/3rdParty/velocypack/include/velocypack/Dumper.h b/3rdParty/velocypack/include/velocypack/Dumper.h index 65fa4bcaaf..5fd4f4d7a9 100644 --- a/3rdParty/velocypack/include/velocypack/Dumper.h +++ b/3rdParty/velocypack/include/velocypack/Dumper.h @@ -43,18 +43,26 @@ namespace arangodb { public: - Options options; + Options const* options; Dumper (Dumper const&) = delete; Dumper& operator= (Dumper const&) = delete; - Dumper (Sink* sink, Options const& options = Options::Defaults) + Dumper (Sink* sink, Options const* options = &Options::Defaults) : options(options), _sink(sink), _indentation(0) { + + if (options == nullptr) { + throw Exception(Exception::InternalError, "Options cannot be a nullptr"); + } } ~Dumper () { } + Sink* sink () const { + return _sink; + } + void dump (Slice const& slice) { _indentation = 0; _sink->reserve(slice.byteSize()); @@ -65,22 +73,23 @@ namespace arangodb { dump(*slice); } - static void dump (Slice const& slice, Sink* sink, Options const& options = Options::Defaults) { + static void dump (Slice const& slice, Sink* sink, Options const* options = &Options::Defaults) { Dumper dumper(sink, options); dumper.dump(slice); } - static void dump (Slice const* slice, Sink* sink, Options const& options = Options::Defaults) { + static void dump (Slice const* slice, Sink* sink, Options const* options = &Options::Defaults) { dump(*slice, sink, options); } - static std::string toString (Slice const& slice, Options const& options = Options::Defaults) { - StringSink sink; + static std::string toString (Slice const& slice, Options const* options = &Options::Defaults) { + std::string buffer; + StringSink sink(&buffer); dump(slice, &sink, options); - return std::move(sink.buffer); + return std::move(buffer); } - static std::string toString (Slice const* slice, Options const& options = Options::Defaults) { + static std::string toString (Slice const* slice, Options const* options = &Options::Defaults) { return std::move(toString(*slice, options)); } @@ -127,7 +136,7 @@ namespace arangodb { } void handleUnsupportedType (Slice const*) { - if (options.unsupportedTypeBehavior == NullifyUnsupportedType) { + if (options->unsupportedTypeBehavior == NullifyUnsupportedType) { _sink->append("null", 4); return; } diff --git a/3rdParty/velocypack/include/velocypack/Iterator.h b/3rdParty/velocypack/include/velocypack/Iterator.h index 00d81a5dae..10b512d935 100644 --- a/3rdParty/velocypack/include/velocypack/Iterator.h +++ b/3rdParty/velocypack/include/velocypack/Iterator.h @@ -42,33 +42,56 @@ namespace arangodb { ArrayIterator () = delete; ArrayIterator (Slice const& slice) - : _slice(slice), _size(_slice.length()), _position(0) { + : _slice(slice), _size(_slice.length()), _position(0), _current(nullptr) { if (slice.type() != ValueType::Array) { throw Exception(Exception::InvalidValueType, "Expecting Array slice"); } + + if (slice.head() == 0x13 && slice.length() > 0) { + _current = slice.at(0).start(); + } } ArrayIterator (ArrayIterator const& other) - : _slice(other._slice), _size(other._size), _position(other._position) { + : _slice(other._slice), _size(other._size), _position(other._position), _current(other._current) { } ArrayIterator& operator= (ArrayIterator const& other) { _slice = other._slice; _size = other._size; _position = other._position; + _current = other._current; return *this; } - Slice operator++ () { - return _slice.at(_position++); + // prefix ++ + ArrayIterator& operator++ () { + ++_position; + if (_position <= _size && _current != nullptr) { + _current += Slice(_current, _slice.options).byteSize(); + } + else { + _current = nullptr; + } + return *this; + } + + // postfix ++ + ArrayIterator operator++ (int) { + ArrayIterator result(*this); + ++(*this); + return result; } bool operator!= (ArrayIterator const& other) const { return _position != other._position; } - Slice operator* () const { + Slice operator* () const { + if (_current != nullptr) { + return Slice(_current, _slice.options); + } return _slice.at(_position); } @@ -100,19 +123,32 @@ namespace arangodb { if (_position >= _size) { throw Exception(Exception::IndexOutOfBounds); } - return _slice.at(_position); + return operator*(); } inline bool next () throw() { - ++_position; + operator++(); return valid(); } + + inline ValueLength index () const throw() { + return _position; + } + + inline bool isFirst () const throw() { + return (_position == 0); + } + + inline bool isLast () const throw() { + return (_position + 1 >= _size); + } private: Slice _slice; ValueLength _size; ValueLength _position; + uint8_t const* _current; }; class ObjectIterator { @@ -130,28 +166,49 @@ namespace arangodb { ObjectIterator () = delete; ObjectIterator (Slice const& slice) - : _slice(slice), _size(_slice.length()), _position(0) { + : _slice(slice), _size(_slice.length()), _position(0), _current(nullptr) { if (slice.type() != ValueType::Object) { throw Exception(Exception::InvalidValueType, "Expecting Object slice"); } + + if (slice.head() == 0x14 && slice.length() > 0) { + _current = slice.keyAt(0).start(); + } } ObjectIterator (ObjectIterator const& other) - : _slice(other._slice), _size(other._size), _position(other._position) { + : _slice(other._slice), _size(other._size), _position(other._position), _current(other._current) { } ObjectIterator& operator= (ObjectIterator const& other) { _slice = other._slice; _size = other._size; _position = other._position; + _current = other._current; return *this; } - ObjectPair operator++ () { - ObjectPair current(_slice.keyAt(_position), _slice.valueAt(_position)); + // prefix ++ + ObjectIterator& operator++ () { ++_position; - return current; + if (_position <= _size && _current != nullptr) { + // skip over key + _current += Slice(_current, _slice.options).byteSize(); + // skip over value + _current += Slice(_current, _slice.options).byteSize(); + } + else { + _current = nullptr; + } + return *this; + } + + // postfix ++ + ObjectIterator operator++ (int) { + ObjectIterator result(*this); + ++(*this); + return result; } bool operator!= (ObjectIterator const& other) const { @@ -159,6 +216,10 @@ namespace arangodb { } ObjectPair operator* () const { + if (_current != nullptr) { + Slice key = Slice(_current, _slice.options); + return ObjectPair(key, Slice(_current + key.byteSize(), _slice.options)); + } return ObjectPair(_slice.keyAt(_position), _slice.valueAt(_position)); } @@ -190,6 +251,9 @@ namespace arangodb { if (_position >= _size) { throw Exception(Exception::IndexOutOfBounds); } + if (_current != nullptr) { + return Slice(_current, _slice.options); + } return _slice.keyAt(_position); } @@ -197,19 +261,36 @@ namespace arangodb { if (_position >= _size) { throw Exception(Exception::IndexOutOfBounds); } + if (_current != nullptr) { + Slice key = Slice(_current, _slice.options); + return Slice(_current + key.byteSize(), _slice.options); + } return _slice.valueAt(_position); } inline bool next () throw() { - ++_position; + operator++(); return valid(); } + inline ValueLength index () const throw() { + return _position; + } + + inline bool isFirst () const throw() { + return (_position == 0); + } + + inline bool isLast () const throw() { + return (_position + 1 >= _size); + } + private: Slice _slice; ValueLength _size; ValueLength _position; + uint8_t const* _current; }; } // namespace arangodb::velocypack diff --git a/3rdParty/velocypack/include/velocypack/Options.h b/3rdParty/velocypack/include/velocypack/Options.h index 13917495e1..0d86d8dfa1 100644 --- a/3rdParty/velocypack/include/velocypack/Options.h +++ b/3rdParty/velocypack/include/velocypack/Options.h @@ -31,7 +31,7 @@ namespace arangodb { namespace velocypack { - struct Sink; + class Dumper; class Slice; struct AttributeExcludeHandler { @@ -45,7 +45,7 @@ namespace arangodb { virtual ~CustomTypeHandler () { } - virtual void toJson (Slice const& value, Sink* sink, Slice const& base) = 0; + virtual void toJson (Slice const& value, Dumper* dumper, Slice const& base) = 0; virtual ValueLength byteSize (Slice const& value) = 0; }; @@ -68,6 +68,12 @@ namespace arangodb { // custom type handler used for processing custom types by Dumper and Slicer CustomTypeHandler* customTypeHandler = nullptr; + // allow building Arrays without index table? + bool buildUnindexedArrays = false; + + // allow building Objects without index table? + bool buildUnindexedObjects = false; + // pretty-print JSON output when dumping with Dumper bool prettyPrint = false; diff --git a/3rdParty/velocypack/include/velocypack/Parser.h b/3rdParty/velocypack/include/velocypack/Parser.h index 57cc00d557..49ae6fe562 100644 --- a/3rdParty/velocypack/include/velocypack/Parser.h +++ b/3rdParty/velocypack/include/velocypack/Parser.h @@ -84,7 +84,7 @@ namespace arangodb { bool isInteger; }; - Builder _b; + Builder _b; uint8_t const* _start; size_t _size; size_t _pos; @@ -92,22 +92,28 @@ namespace arangodb { public: - Options options; + Options const* options; Parser (Parser const&) = delete; Parser& operator= (Parser const&) = delete; - Parser () : _start(nullptr), _size(0), _pos(0), _nesting(0) { + Parser (Options const* options = &Options::Defaults) + : _start(nullptr), _size(0), _pos(0), _nesting(0), options(options) { + + VELOCYPACK_ASSERT(options != nullptr); + if (options == nullptr) { + throw Exception(Exception::InternalError, "Options cannot be a nullptr"); + } } - static Builder fromJson (std::string const& json, Options const& options = Options::Defaults) { + static Builder fromJson (std::string const& json, Options const* options = &Options::Defaults) { Parser parser; parser.options = options; parser.parse(json); return parser.steal(); } - static Builder fromJson (uint8_t const* start, size_t size, Options const& options = Options::Defaults) { + static Builder fromJson (uint8_t const* start, size_t size, Options const* options = &Options::Defaults) { Parser parser; parser.options = options; parser.parse(start, size); @@ -115,12 +121,12 @@ namespace arangodb { } ValueLength parse (std::string const& json, bool multi = false) { - _start = reinterpret_cast(json.c_str()); - _size = json.size(); - _pos = 0; - _b.clear(); - _b.options = options; - return parseInternal(multi); + return parse(reinterpret_cast(json.c_str()), json.size(), multi); + } + + ValueLength parse (char const* start, size_t size, + bool multi = false) { + return parse(reinterpret_cast(start), size, multi); } ValueLength parse (uint8_t const* start, size_t size, @@ -133,20 +139,13 @@ namespace arangodb { return parseInternal(multi); } - ValueLength parse (char const* start, size_t size, - bool multi = false) { - _start = reinterpret_cast(start); - _size = size; - _pos = 0; - _b.clear(); - _b.options = options; - return parseInternal(multi); - } - // We probably want a parse from stream at some stage... // Not with this high-performance two-pass approach. :-( Builder&& steal () { + if (_b._buffer == nullptr) { + throw Exception(Exception::InternalError, "Buffer of Builder is already gone"); + } return std::move(_b); } diff --git a/3rdParty/velocypack/include/velocypack/Sink.h b/3rdParty/velocypack/include/velocypack/Sink.h index cc289ae21f..9b54d8b8ba 100644 --- a/3rdParty/velocypack/include/velocypack/Sink.h +++ b/3rdParty/velocypack/include/velocypack/Sink.h @@ -28,6 +28,8 @@ #define VELOCYPACK_SINK_H 1 #include +#include +#include #include "velocypack/velocypack-common.h" #include "velocypack/Buffer.h" @@ -51,71 +53,70 @@ namespace arangodb { }; template - struct ByteBufferSink final : public Sink { - ByteBufferSink () - : buffer() { - } - - ByteBufferSink (ValueLength size) - : buffer(size) { - } - - void push_back (char c) override final { - buffer.push_back(c); - } - - void append (std::string const& p) override final { - buffer.append(p.c_str(), p.size()); - } - - void append (char const* p) override final { - buffer.append(p, strlen(p)); - } - - void append (char const* p, ValueLength len) override final { - buffer.append(p, len); - } - - void reserve (ValueLength len) override final { - buffer.reserve(len); - } - - Buffer buffer; - }; - - struct StringSink final : public Sink { - StringSink () - : buffer() { + struct ByteBufferSinkImpl final : public Sink { + explicit ByteBufferSinkImpl (Buffer* buffer) + : buffer(buffer) { } void push_back (char c) override final { - buffer.push_back(c); + buffer->push_back(c); } void append (std::string const& p) override final { - buffer.append(p); + buffer->append(p.c_str(), p.size()); } void append (char const* p) override final { - buffer.append(p, strlen(p)); + buffer->append(p, strlen(p)); } void append (char const* p, ValueLength len) override final { - buffer.append(p, len); + buffer->append(p, len); } void reserve (ValueLength len) override final { - buffer.reserve(len); + buffer->reserve(len); } - std::string buffer; + Buffer* buffer; }; - - typedef ByteBufferSink CharBufferSink; + + typedef ByteBufferSinkImpl CharBufferSink; template - struct StreamSink final : public Sink { - StreamSink (T* stream) + struct StringSinkImpl final : public Sink { + explicit StringSinkImpl (T* buffer) + : buffer(buffer) { + } + + void push_back (char c) override final { + buffer->push_back(c); + } + + void append (std::string const& p) override final { + buffer->append(p); + } + + void append (char const* p) override final { + buffer->append(p, strlen(p)); + } + + void append (char const* p, ValueLength len) override final { + buffer->append(p, len); + } + + void reserve (ValueLength len) override final { + buffer->reserve(len); + } + + T* buffer; + }; + + typedef StringSinkImpl StringSink; + + template + struct StreamSinkImpl final : public Sink { + explicit StreamSinkImpl (T* stream) : stream(stream) { } @@ -140,6 +141,9 @@ namespace arangodb { T* stream; }; + + typedef StreamSinkImpl StringStreamSink; + typedef StreamSinkImpl OutputFileStreamSink; } // namespace arangodb::velocypack } // namespace arangodb diff --git a/3rdParty/velocypack/include/velocypack/Slice.h b/3rdParty/velocypack/include/velocypack/Slice.h index 4c8031c96f..1c78d346ed 100644 --- a/3rdParty/velocypack/include/velocypack/Slice.h +++ b/3rdParty/velocypack/include/velocypack/Slice.h @@ -58,28 +58,44 @@ namespace arangodb { public: - CustomTypeHandler* customTypeHandler; + Options const* options; // constructor for an empty Value of type None Slice () - : Slice("\x00") { + : Slice("\x00", &Options::Defaults) { } - explicit Slice (uint8_t const* start, CustomTypeHandler* handler = nullptr) - : _start(start), customTypeHandler(handler) { + explicit Slice (uint8_t const* start, Options const* options = &Options::Defaults) + : _start(start), options(options) { + VELOCYPACK_ASSERT(options != nullptr); } - explicit Slice (char const* start, CustomTypeHandler* handler = nullptr) - : _start(reinterpret_cast(start)), customTypeHandler(handler) { + explicit Slice (char const* start, Options const* options = &Options::Defaults) + : _start(reinterpret_cast(start)), options(options) { + VELOCYPACK_ASSERT(options != nullptr); } Slice (Slice const& other) - : _start(other._start), customTypeHandler(other.customTypeHandler) { + : _start(other._start), options(other.options) { + VELOCYPACK_ASSERT(options != nullptr); + } + + Slice (Slice&& other) + : _start(other._start), options(other.options) { + VELOCYPACK_ASSERT(options != nullptr); } Slice& operator= (Slice const& other) { _start = other._start; - customTypeHandler = other.customTypeHandler; + options = other.options; + VELOCYPACK_ASSERT(options != nullptr); + return *this; + } + + Slice& operator= (Slice&& other) { + _start = other._start; + options = other.options; + VELOCYPACK_ASSERT(options != nullptr); return *this; } @@ -299,13 +315,19 @@ namespace arangodb { return 0; } + if (h == 0x13 || h == 0x14) { + // compact Array or Object + ValueLength end = readVariableValueLength(_start + 1); + return readVariableValueLength(_start + end - 1); + } + ValueLength const offsetSize = indexEntrySize(h); ValueLength end = readInteger(_start + 1, offsetSize); // find number of items if (h <= 0x05) { // No offset table or length, need to compute: ValueLength firstSubOffset = findDataOffset(h); - Slice first(_start + firstSubOffset, customTypeHandler); + Slice first(_start + firstSubOffset, options); return (end - firstSubOffset) / first.byteSize(); } else if (offsetSize < 8) { @@ -335,7 +357,7 @@ namespace arangodb { Slice valueAt (ValueLength index) const { Slice key = keyAt(index); - return Slice(key.start() + key.byteSize(), customTypeHandler); + return Slice(key.start() + key.byteSize(), options); } // look for the specified attribute path inside an Object @@ -347,7 +369,7 @@ namespace arangodb { } // use ourselves as the starting point - Slice last = Slice(start(), customTypeHandler); + Slice last = Slice(start(), options); for (size_t i = 0; i < attributes.size(); ++i) { // fetch subattribute last = last.get(attributes[i]); @@ -363,72 +385,7 @@ namespace arangodb { // look for the specified attribute inside an Object // returns a Slice(ValueType::None) if not found - Slice get (std::string const& attribute) const { - if (! isType(ValueType::Object)) { - throw Exception(Exception::InvalidValueType, "Expecting Object"); - } - - auto const h = head(); - if (h == 0xa) { - // special case, empty object - return Slice(); - } - - ValueLength const offsetSize = indexEntrySize(h); - ValueLength end = readInteger(_start + 1, offsetSize); - ValueLength dataOffset = 0; - - // read number of items - ValueLength n; - if (h <= 0x05) { // No offset table or length, need to compute: - dataOffset = findDataOffset(h); - Slice first(_start + dataOffset, customTypeHandler); - n = (end - dataOffset) / first.byteSize(); - } - else if (offsetSize < 8) { - n = readInteger(_start + 1 + offsetSize, offsetSize); - } - else { - n = readInteger(_start + end - offsetSize, offsetSize); - } - - if (n == 1) { - // Just one attribute, there is no index table! - if (dataOffset == 0) { - dataOffset = findDataOffset(h); - } - Slice attrName = Slice(_start + dataOffset, customTypeHandler); - if (! attrName.isString()) { - return Slice(); - } - ValueLength attrLength; - char const* k = attrName.getString(attrLength); - if (attrLength != static_cast(attribute.size())) { - // key must have the exact same length as the attribute we search for - return Slice(); - } - if (memcmp(k, attribute.c_str(), attribute.size()) != 0) { - return Slice(); - } - - return Slice(attrName.start() + attrName.byteSize(), customTypeHandler); - } - - ValueLength const ieBase = end - n * offsetSize - - (offsetSize == 8 ? offsetSize : 0); - - // only use binary search for attributes if we have at least this many entries - // otherwise we'll always use the linear search - static ValueLength const SortedSearchEntriesThreshold = 4; - - if (isSorted() && n >= SortedSearchEntriesThreshold) { - // This means, we have to handle the special case n == 1 only - // in the linear search! - return searchObjectKeyBinary(attribute, ieBase, offsetSize, n); - } - - return searchObjectKeyLinear(attribute, ieBase, offsetSize, n); - } + Slice get (std::string const& attribute) const; Slice operator[] (std::string const& attribute) const { return get(attribute); @@ -450,91 +407,13 @@ namespace arangodb { } // return the value for an Int object - int64_t getInt () const { - uint8_t const h = head(); - if (h >= 0x20 && h <= 0x27) { - // Int T - uint64_t v = readInteger(_start + 1, h - 0x1f); - if (h == 0x27) { - return ToInt64(v); - } - else { - int64_t vv = static_cast(v); - int64_t shift = 1LL << ((h - 0x1f) * 8 - 1); - return vv < shift ? vv : vv - (shift << 1); - } - } - - if (h >= 0x28 && h <= 0x2f) { - // UInt - uint64_t v = getUInt(); - if (v > static_cast(INT64_MAX)) { - throw Exception(Exception::NumberOutOfRange); - } - return static_cast(v); - } - - if (h >= 0x30 && h <= 0x3f) { - // SmallInt - return getSmallInt(); - } - - throw Exception(Exception::InvalidValueType, "Expecting type Int"); - } + int64_t getInt () const; // return the value for a UInt object - uint64_t getUInt () const { - uint8_t const h = head(); - if (h >= 0x28 && h <= 0x2f) { - // UInt - return readInteger(_start + 1, h - 0x27); - } - - if (h >= 0x20 && h <= 0x27) { - // Int - int64_t v = getInt(); - if (v < 0) { - throw Exception(Exception::NumberOutOfRange); - } - return static_cast(v); - } - - if (h >= 0x30 && h <= 0x39) { - // Smallint >= 0 - return static_cast(h - 0x30); - } - - if (h >= 0x3a && h <= 0x3f) { - // Smallint < 0 - throw Exception(Exception::NumberOutOfRange); - } - - throw Exception(Exception::InvalidValueType, "Expecting type UInt"); - } + uint64_t getUInt () const; // return the value for a SmallInt object - int64_t getSmallInt () const { - uint8_t const h = head(); - - if (h >= 0x30 && h <= 0x39) { - // Smallint >= 0 - return static_cast(h - 0x30); - } - - if (h >= 0x3a && h <= 0x3f) { - // Smallint < 0 - return static_cast(h - 0x3a) - 6; - } - - if ((h >= 0x20 && h <= 0x27) || - (h >= 0x28 && h <= 0x2f)) { - // Int and UInt - // we'll leave it to the compiler to detect the two ranges above are adjacent - return getInt(); - } - - throw Exception(Exception::InvalidValueType, "Expecting type Smallint"); - } + int64_t getSmallInt () const; template T getNumericValue () const { @@ -596,7 +475,7 @@ namespace arangodb { int64_t getUTCDate () const { assertType(ValueType::UTCDate); uint64_t v = readInteger(_start + 1, sizeof(uint64_t)); - return ToInt64(v); + return toInt64(v); } // return the value for a String object @@ -611,7 +490,7 @@ namespace arangodb { if (h == 0xbf) { // long UTF-8 String length = readInteger(_start + 1, 8); - CheckValueLength(length); + checkValueLength(length); return reinterpret_cast(_start + 1 + 8); } @@ -629,7 +508,7 @@ namespace arangodb { if (h == 0xbf) { ValueLength length = readInteger(_start + 1, 8); - CheckValueLength(length); + checkValueLength(length); return std::string(reinterpret_cast(_start + 1 + 8), length); } @@ -643,7 +522,7 @@ namespace arangodb { if (h >= 0xc0 && h <= 0xc7) { length = readInteger(_start + 1, h - 0xbf); - CheckValueLength(length); + checkValueLength(length); return _start + 1 + h - 0xbf; } @@ -658,7 +537,7 @@ namespace arangodb { if (h >= 0xc0 && h <= 0xc7) { std::vector out; ValueLength length = readInteger(_start + 1, h - 0xbf); - CheckValueLength(length); + checkValueLength(length); out.reserve(static_cast(length)); out.insert(out.end(), _start + 1 + h - 0xbf, _start + 1 + h - 0xbf + length); return out; @@ -687,10 +566,16 @@ namespace arangodb { case ValueType::Object: { auto const h = head(); if (h == 0x01 || h == 0x0a) { - // empty array or object + // empty Array or Object return 1; } + if (h == 0x13 || h == 0x14) { + // compact Array or Object + return readVariableValueLength(_start + 1); + } + + VELOCYPACK_ASSERT(h <= 0x12); return readInteger(_start + 1, WidthMap[h]); } @@ -738,11 +623,11 @@ namespace arangodb { } case ValueType::Custom: { - if (customTypeHandler == nullptr) { + if (options->customTypeHandler == nullptr) { throw Exception(Exception::NeedCustomTypeHandler); } - return customTypeHandler->byteSize(*this); + return options->customTypeHandler->byteSize(*this); } } @@ -750,14 +635,21 @@ namespace arangodb { return 0; } + int compareString (std::string const& attribute) const; + bool isEqualString (std::string const& attribute) const; + + std::string toJson () const; std::string toString () const; std::string hexType () const; private: - - ValueLength findDataOffset (uint8_t const head) const { + + Slice getFromCompactObject (std::string const& attribute) const; + + ValueLength findDataOffset (uint8_t head) const { // Must be called for a nonempty array or object at start(): + VELOCYPACK_ASSERT(head <= 0x12); unsigned int fsm = FirstSubMap[head]; if (fsm <= 2 && _start[2] != 0) { return 2; @@ -770,139 +662,40 @@ namespace arangodb { } return 9; } + + ValueLength valueOffset (ValueLength index) const { + if (type() != ValueType::Array && type() != ValueType::Object) { + throw Exception(Exception::InvalidValueType, "Expecting Array or Object"); + } + + return getNthOffset(index); + } + + // get the offset for the nth member from an Array or Object type + ValueLength getNthOffset (ValueLength index) const; // extract the nth member from an Array or Object type - Slice getNth (ValueLength index) const { - VELOCYPACK_ASSERT(type() == ValueType::Array || type() == ValueType::Object); - - auto const h = head(); - if (h == 0x01 || h == 0x0a) { - // special case. empty array or object - throw Exception(Exception::IndexOutOfBounds); - } - - ValueLength const offsetSize = indexEntrySize(h); - ValueLength end = readInteger(_start + 1, offsetSize); - - ValueLength dataOffset = findDataOffset(h); - - // find the number of items - ValueLength n; - if (h <= 0x05) { // No offset table or length, need to compute: - Slice first(_start + dataOffset, customTypeHandler); - n = (end - dataOffset) / first.byteSize(); - } - else if (offsetSize < 8) { - n = readInteger(_start + 1 + offsetSize, offsetSize); - } - else { - n = readInteger(_start + end - offsetSize, offsetSize); - } - - if (index >= n) { - throw Exception(Exception::IndexOutOfBounds); - } - - // empty array case was already covered - VELOCYPACK_ASSERT(n > 0); - - if (h <= 0x05 || n == 1) { - // no index table, but all array items have the same length - // now fetch first item and determine its length - if (dataOffset == 0) { - dataOffset = findDataOffset(h); - } - Slice firstItem(_start + dataOffset, customTypeHandler); - return Slice(_start + dataOffset + index * firstItem.byteSize(), customTypeHandler); - } - - ValueLength const ieBase = end - n * offsetSize + index * offsetSize - - (offsetSize == 8 ? 8 : 0); - return Slice(_start + readInteger(_start + ieBase, offsetSize), customTypeHandler); - } + Slice getNth (ValueLength index) const; + + // get the offset for the nth member from a compact Array or Object type + ValueLength getNthOffsetFromCompact (ValueLength index) const; ValueLength indexEntrySize (uint8_t head) const { + VELOCYPACK_ASSERT(head <= 0x12); return static_cast(WidthMap[head]); } // perform a linear search for the specified attribute inside an Object Slice searchObjectKeyLinear (std::string const& attribute, - ValueLength ieBase, - ValueLength offsetSize, - ValueLength n) const { - for (ValueLength index = 0; index < n; ++index) { - ValueLength offset = ieBase + index * offsetSize; - Slice key(_start + readInteger(_start + offset, offsetSize), customTypeHandler); - if (! key.isString()) { - // invalid object - return Slice(); - } - - ValueLength keyLength; - char const* k = key.getString(keyLength); - if (keyLength != static_cast(attribute.size())) { - // key must have the exact same length as the attribute we search for - continue; - } - - if (memcmp(k, attribute.c_str(), attribute.size()) != 0) { - continue; - } - // key is identical. now return value - return Slice(key.start() + key.byteSize(), customTypeHandler); - } - - // nothing found - return Slice(); - } + ValueLength ieBase, + ValueLength offsetSize, + ValueLength n) const; // perform a binary search for the specified attribute inside an Object Slice searchObjectKeyBinary (std::string const& attribute, - ValueLength ieBase, - ValueLength offsetSize, - ValueLength n) const { - VELOCYPACK_ASSERT(n > 0); - - ValueLength const attributeLength = static_cast(attribute.size()); - - ValueLength l = 0; - ValueLength r = n - 1; - - while (true) { - // midpoint - ValueLength index = l + ((r - l) / 2); - - ValueLength offset = ieBase + index * offsetSize; - Slice key(_start + readInteger(_start + offset, offsetSize), customTypeHandler); - if (! key.isString()) { - // invalid object - return Slice(); - } - - ValueLength keyLength; - char const* k = key.getString(keyLength); - size_t const compareLength = static_cast((std::min)(keyLength, attributeLength)); - int res = memcmp(k, attribute.c_str(), compareLength); - - if (res == 0 && keyLength == attributeLength) { - // key is identical. now return value - return Slice(key.start() + key.byteSize(), customTypeHandler); - } - - if (res > 0 || (res == 0 && keyLength > attributeLength)) { - if (index == 0) { - return Slice(); - } - r = index - 1; - } - else { - l = index + 1; - } - if (r < l) { - return Slice(); - } - } - } + ValueLength ieBase, + ValueLength offsetSize, + ValueLength n) const; // assert that the slice is of a specific type // can be used for debugging and removed in production @@ -947,8 +740,8 @@ namespace arangodb { private: static ValueType const TypeMap[256]; - static unsigned int const WidthMap[256]; - static unsigned int const FirstSubMap[256]; + static unsigned int const WidthMap[32]; + static unsigned int const FirstSubMap[32]; }; } // namespace arangodb::velocypack diff --git a/3rdParty/velocypack/include/velocypack/Value.h b/3rdParty/velocypack/include/velocypack/Value.h index 9e07cce82d..f8c46dce44 100644 --- a/3rdParty/velocypack/include/velocypack/Value.h +++ b/3rdParty/velocypack/include/velocypack/Value.h @@ -67,48 +67,65 @@ namespace arangodb { std::string const* s; // 5: std::string char const* c; // 6: char const* void const* e; // external - } _value; + } + _value; + + bool _unindexed; public: Value () = delete; - explicit Value (ValueType t) - : _valueType(t), _cType(CType::None) { + // creates a Value with the specified type Array or Object + explicit Value (ValueType t, bool allowUnindexed = false) + : _valueType(t), _cType(CType::None), _unindexed(allowUnindexed) { + + if (allowUnindexed && + (_valueType != ValueType::Array && _valueType != ValueType::Object)) { + throw Exception(Exception::InvalidValueType, "Expecting compound type"); + } } explicit Value (bool b, ValueType t = ValueType::Bool) - : _valueType(t), _cType(CType::Bool) { + : _valueType(t), _cType(CType::Bool), _unindexed(false) { _value.b = b; } + explicit Value (double d, ValueType t = ValueType::Double) - : _valueType(t), _cType(CType::Double) { + : _valueType(t), _cType(CType::Double), _unindexed(false) { _value.d = d; } + explicit Value (void const* e, ValueType t = ValueType::External) - : _valueType(t), _cType(CType::VoidPtr) { + : _valueType(t), _cType(CType::VoidPtr), _unindexed(false) { _value.e = e; } + explicit Value (char const* c, ValueType t = ValueType::String) - : _valueType(t), _cType(CType::CharPtr) { + : _valueType(t), _cType(CType::CharPtr), _unindexed(false) { _value.c = c; } + explicit Value (int32_t i, ValueType t = ValueType::Int) - : _valueType(t), _cType(CType::Int64) { + : _valueType(t), _cType(CType::Int64), _unindexed(false) { _value.i = static_cast(i); } + explicit Value (uint32_t u, ValueType t = ValueType::UInt) - : _valueType(t), _cType(CType::UInt64) { + : _valueType(t), _cType(CType::UInt64), _unindexed(false) { _value.u = static_cast(u); } + explicit Value (int64_t i, ValueType t = ValueType::Int) - : _valueType(t), _cType(CType::Int64) { + : _valueType(t), _cType(CType::Int64), _unindexed(false) { _value.i = i; } + explicit Value (uint64_t u, ValueType t = ValueType::UInt) - : _valueType(t), _cType(CType::UInt64) { + : _valueType(t), _cType(CType::UInt64), _unindexed(false) { _value.u = u; } + #ifdef __APPLE__ // MacOS uses the following typedefs: // - typedef unsigned int uint32_t; @@ -120,12 +137,13 @@ namespace arangodb { // however, defining the method on Linux and with MSVC will lead // to ambiguous overloads, so this is restricted to __APPLE__ only explicit Value (unsigned long i, ValueType t = ValueType::Int) - : _valueType(t), _cType(CType::UInt64) { + : _valueType(t), _cType(CType::UInt64), _unindexed(false) { _value.i = static_cast(i); } -#endif +#endif + explicit Value (std::string const& s, ValueType t = ValueType::String) - : _valueType(t), _cType(CType::String) { + : _valueType(t), _cType(CType::String), _unindexed(false) { _value.s = &s; } diff --git a/3rdParty/velocypack/include/velocypack/velocypack-aliases.h b/3rdParty/velocypack/include/velocypack/velocypack-aliases.h index 0378d0f815..53a3955d97 100644 --- a/3rdParty/velocypack/include/velocypack/velocypack-aliases.h +++ b/3rdParty/velocypack/include/velocypack/velocypack-aliases.h @@ -43,6 +43,7 @@ using VPackParser = arangodb::velocypack::Parser; using VPackSink = arangodb::velocypack::Sink; using VPackSlice = arangodb::velocypack::Slice; using VPackStringSink = arangodb::velocypack::StringSink; +using VPackStringStreamSink = arangodb::velocypack::StringStreamSink; using VPackValue = arangodb::velocypack::Value; using VPackValueLength = arangodb::velocypack::ValueLength; using VPackValueType = arangodb::velocypack::ValueType; diff --git a/3rdParty/velocypack/include/velocypack/velocypack-common.h b/3rdParty/velocypack/include/velocypack/velocypack-common.h index 0246bb5173..78ecb65c89 100644 --- a/3rdParty/velocypack/include/velocypack/velocypack-common.h +++ b/3rdParty/velocypack/include/velocypack/velocypack-common.h @@ -75,17 +75,69 @@ namespace arangodb { #ifndef VELOCYPACK_64BIT // check if the length is beyond the size of a SIZE_MAX on this platform - static void CheckValueLength (ValueLength); + static void checkValueLength (ValueLength); #else - static inline void CheckValueLength (ValueLength) { + static inline void checkValueLength (ValueLength) { // do nothing on a 64 bit platform } #endif - // returns current value for UTCDate - int64_t CurrentUTCDateValue (); + // calculate the length of a variable length integer in unsigned LEB128 format + static inline ValueLength getVariableValueLength (ValueLength value) throw() { + ValueLength len = 1; + while (value >= 0x80) { + value >>= 7; + ++len; + } + return len; + } - static inline uint64_t ToUInt64 (int64_t v) { + // read a variable length integer in unsigned LEB128 format + template + static inline ValueLength readVariableValueLength (uint8_t const* source) { + ValueLength len = 0; + uint8_t v; + ValueLength p = 0; + do { + v = *source; + len += (v & 0x7f) << p; + p += 7; + if (reverse) { + --source; + } + else { + ++source; + } + } + while (v & 0x80); + return len; + } + + // store a variable length integer in unsigned LEB128 format + template + static inline void storeVariableValueLength (uint8_t* dst, ValueLength value) { + VELOCYPACK_ASSERT(value > 0); + + if (reverse) { + while (value >= 0x80) { + *dst-- = static_cast(value | 0x80); + value >>= 7; + } + *dst-- = static_cast(value & 0x7f); + } + else { + while (value >= 0x80) { + *dst++ = static_cast(value | 0x80); + value >>= 7; + } + *dst++ = static_cast(value & 0x7f); + } + } + + // returns current value for UTCDate + int64_t currentUTCDateValue (); + + static inline uint64_t toUInt64 (int64_t v) throw() { // If v is negative, we need to add 2^63 to make it positive, // before we can cast it to an uint64_t: uint64_t shift2 = 1ULL << 63; @@ -97,7 +149,7 @@ namespace arangodb { // uint64_t is not guaranteed to work for negative values! } - static inline int64_t ToInt64 (uint64_t v) { + static inline int64_t toInt64 (uint64_t v) throw() { uint64_t shift2 = 1ULL << 63; int64_t shift = static_cast(shift2 - 1); return v >= shift2 ? (static_cast(v - shift2) - shift) - 1 diff --git a/3rdParty/velocypack/src/Builder.cpp b/3rdParty/velocypack/src/Builder.cpp index ff4eebe2c8..df7617db84 100644 --- a/3rdParty/velocypack/src/Builder.cpp +++ b/3rdParty/velocypack/src/Builder.cpp @@ -151,12 +151,17 @@ void Builder::close () { throw Exception(Exception::BuilderNeedOpenCompound); } ValueLength& tos = _stack.back(); - if (_start[tos] != 0x06 && _start[tos] != 0x0b) { + uint8_t const head = _start[tos]; + + if (head != 0x06 && head != 0x0b && head != 0x13 && head != 0x14) { throw Exception(Exception::BuilderNeedOpenObject); } + bool const isArray = (head == 0x06 || head == 0x13); std::vector& index = _index[_stack.size() - 1]; + if (index.empty()) { - _start[tos] = (_start[tos] == 0x06) ? 0x01 : 0x0a; + // empty Array or Object + _start[tos] = (isArray ? 0x01 : 0x0a); VELOCYPACK_ASSERT(_pos == tos + 9); _pos -= 8; // no bytelength and number subvalues needed _stack.pop_back(); @@ -167,6 +172,54 @@ void Builder::close () { // From now on index.size() > 0 VELOCYPACK_ASSERT(index.size() > 0); + // check if we can use the compact Array / Object format + if (index.size() > 1 && + ((head == 0x13 || head == 0x14) || + (head == 0x06 && options->buildUnindexedArrays) || + (head == 0x0b && options->buildUnindexedObjects))) { + // use compact notation + ValueLength nLen = getVariableValueLength(static_cast(index.size())); + VELOCYPACK_ASSERT(nLen > 0); + ValueLength byteSize = _pos - (tos + 8) + nLen; + VELOCYPACK_ASSERT(byteSize > 0); + ValueLength bLen = getVariableValueLength(byteSize); + byteSize += bLen; + if (getVariableValueLength(byteSize) != bLen) { + byteSize += 1; + bLen += 1; + } + + if (bLen < 9) { + // can only use compact notation if total byte length is at most 8 bytes long + _start[tos] = (isArray ? 0x13 : 0x14); + ValueLength targetPos = 1 + bLen; + + if (_pos > (tos + 9)) { + memmove(_start + tos + targetPos, _start + tos + 9, + _pos - (tos + 9)); + } + + // store byte length + VELOCYPACK_ASSERT(byteSize > 0); + storeVariableValueLength(_start + tos + 1, byteSize); + + // need additional memory for storing the number of values + if (nLen > 8 - bLen) { + reserveSpace(nLen); + } + storeVariableValueLength(_start + tos + byteSize - 1, static_cast(index.size())); + + _pos -= 8; + _pos += nLen + bLen; + + _stack.pop_back(); + return; + } + } + + // fix head byte in case a compact Array / Object was originally requested + _start[tos] = (isArray ? 0x06 : 0x0b); + bool needIndexTable = true; bool needNrSubs = true; if (index.size() == 1) { @@ -176,7 +229,7 @@ void Builder::close () { } // For objects we leave needNrSubs at true here! } - else if (_start[tos] == 0x06 && // an array + else if (_start[tos] == 0x06 && // an Array (_pos - tos) - index[0] == index.size() * (index[1] - index[0])) { // In this case it could be that all entries have the same length // and we do not need an offset table at all: @@ -246,12 +299,13 @@ void Builder::close () { reserveSpace(offsetSize * index.size() + (offsetSize == 8 ? 8 : 0)); tableBase = _pos; _pos += offsetSize * index.size(); - if (_start[tos] == 0x0b) { // an object - if (! options.sortAttributeNames) { + if (_start[tos] == 0x0b) { + // Object + if (! options->sortAttributeNames) { _start[tos] = 0x0f; // unsorted } else if (index.size() >= 2 && - options.sortAttributeNames) { + options->sortAttributeNames) { sortObjectIndex(_start + tos, index); } } @@ -300,10 +354,10 @@ void Builder::close () { } // And, if desired, check attribute uniqueness: - if (options.checkAttributeUniqueness && index.size() > 1 && + if (options->checkAttributeUniqueness && index.size() > 1 && _start[tos] >= 0x0b) { // check uniqueness of attribute names - checkAttributeUniqueness(Slice(_start + tos, options.customTypeHandler)); + checkAttributeUniqueness(Slice(_start + tos, options)); } // Now the array or object is complete, we pop a ValueLength @@ -318,7 +372,7 @@ bool Builder::hasKey (std::string const& key) const { throw Exception(Exception::BuilderNeedOpenObject); } ValueLength const& tos = _stack.back(); - if (_start[tos] != 0x06 && _start[tos] != 0x0b) { + if (_start[tos] != 0x0b && _start[tos] != 0x14) { throw Exception(Exception::BuilderNeedOpenObject); } std::vector const& index = _index[_stack.size() - 1]; @@ -326,8 +380,8 @@ bool Builder::hasKey (std::string const& key) const { return false; } for (size_t i = 0; i < index.size(); ++i) { - Slice s(_start + tos + index[i], options.customTypeHandler); - if (s.isString() && s.copyString() == key) { + Slice s(_start + tos + index[i], options); + if (s.isString() && s.isEqualString(key)) { return true; } } @@ -436,7 +490,7 @@ uint8_t* Builder::set (Value const& item) { v = item.getInt64(); break; case Value::CType::UInt64: - v = ToInt64(item.getUInt64()); + v = toInt64(item.getUInt64()); break; default: throw Exception(Exception::BuilderUnexpectedValue, "Must give number for ValueType::Int"); @@ -478,7 +532,7 @@ uint8_t* Builder::set (Value const& item) { v = item.getInt64(); break; case Value::CType::UInt64: - v = ToInt64(item.getUInt64()); + v = toInt64(item.getUInt64()); break; default: throw Exception(Exception::BuilderUnexpectedValue, "Must give number for ValueType::UTCDate"); @@ -518,11 +572,11 @@ uint8_t* Builder::set (Value const& item) { break; } case ValueType::Array: { - addArray(); + addArray(item._unindexed); break; } case ValueType::Object: { - addObject(); + addObject(item._unindexed); break; } case ValueType::Binary: { @@ -620,8 +674,8 @@ uint8_t* Builder::set (ValuePair const& pair) { throw Exception(Exception::BuilderUnexpectedType, "Only ValueType::Binary, ValueType::String and ValueType::Custom are valid for ValuePair argument"); } -void Builder::checkAttributeUniqueness (Slice const obj) const { - VELOCYPACK_ASSERT(options.checkAttributeUniqueness == true); +void Builder::checkAttributeUniqueness (Slice const& obj) const { + VELOCYPACK_ASSERT(options->checkAttributeUniqueness == true); ValueLength const n = obj.length(); if (obj.isSorted()) { diff --git a/3rdParty/velocypack/src/Dumper.cpp b/3rdParty/velocypack/src/Dumper.cpp index 272f337bbc..29107112a2 100644 --- a/3rdParty/velocypack/src/Dumper.cpp +++ b/3rdParty/velocypack/src/Dumper.cpp @@ -28,6 +28,7 @@ #include "velocypack/velocypack-common.h" #include "velocypack/Dumper.h" +#include "velocypack/Iterator.h" #include "velocypack/ValueType.h" using namespace arangodb::velocypack; @@ -141,7 +142,7 @@ void Dumper::dumpString (char const* src, ValueLength len) { char esc = EscapeTable[c]; if (esc) { - if (c != '/' || options.escapeForwardSlashes) { + if (c != '/' || options->escapeForwardSlashes) { // escape forward slashes only when requested _sink->push_back('\\'); } @@ -220,28 +221,30 @@ void Dumper::dumpValue (Slice const* slice, Slice const* base) { } case ValueType::Array: { - ValueLength const n = slice->length(); + ArrayIterator it(*slice); _sink->push_back('['); - if (options.prettyPrint) { + if (options->prettyPrint) { _sink->push_back('\n'); ++_indentation; - for (ValueLength i = 0; i < n; ++i) { + while (it.valid()) { indent(); - dumpValue(slice->at(i), base); - if (i + 1 != n) { + dumpValue(it.value(), base); + if (! it.isLast()) { _sink->push_back(','); } _sink->push_back('\n'); + it.next(); } --_indentation; indent(); } else { - for (ValueLength i = 0; i < n; ++i) { - if (i > 0) { + while (it.valid()) { + if (! it.isFirst()) { _sink->push_back(','); } - dumpValue(slice->at(i), base); + dumpValue(it.value(), base); + it.next(); } } _sink->push_back(']'); @@ -249,32 +252,34 @@ void Dumper::dumpValue (Slice const* slice, Slice const* base) { } case ValueType::Object: { - ValueLength const n = slice->length(); + ObjectIterator it(*slice); _sink->push_back('{'); - if (options.prettyPrint) { + if (options->prettyPrint) { _sink->push_back('\n'); ++_indentation; - for (ValueLength i = 0; i < n; ++i) { + while (it.valid()) { indent(); - dumpValue(slice->keyAt(i), base); + dumpValue(it.key(), base); _sink->append(" : ", 3); - dumpValue(slice->valueAt(i), base); - if (i + 1 != n) { + dumpValue(it.value(), base); + if (! it.isLast()) { _sink->push_back(','); } _sink->push_back('\n'); + it.next(); } --_indentation; indent(); } else { - for (ValueLength i = 0; i < n; ++i) { - if (i > 0) { + while (it.valid()) { + if (! it.isFirst()) { _sink->push_back(','); } - dumpValue(slice->keyAt(i), base); + dumpValue(it.key(), base); _sink->push_back(':'); - dumpValue(slice->valueAt(i), base); + dumpValue(it.value(), base); + it.next(); } } _sink->push_back('}'); @@ -300,7 +305,7 @@ void Dumper::dumpValue (Slice const* slice, Slice const* base) { } case ValueType::External: { - Slice const external(slice->getExternal(), slice->customTypeHandler); + Slice const external(slice->getExternal(), slice->options); dumpValue(&external, base); break; } @@ -339,11 +344,11 @@ void Dumper::dumpValue (Slice const* slice, Slice const* base) { } case ValueType::Custom: { - if (options.customTypeHandler == nullptr) { + if (options->customTypeHandler == nullptr) { handleUnsupportedType(slice); } else { - options.customTypeHandler->toJson(*slice, _sink, *base); + options->customTypeHandler->toJson(*slice, this, *base); } break; } diff --git a/3rdParty/velocypack/src/Parser.cpp b/3rdParty/velocypack/src/Parser.cpp index fb927c2072..adc1087ccf 100644 --- a/3rdParty/velocypack/src/Parser.cpp +++ b/3rdParty/velocypack/src/Parser.cpp @@ -132,7 +132,7 @@ void Parser::parseNumber () { if (numberValue.intValue <= static_cast(INT64_MAX)) { _b.addInt(-static_cast(numberValue.intValue)); } - else if (numberValue.intValue == ToUInt64(INT64_MIN)) { + else if (numberValue.intValue == toUInt64(INT64_MIN)) { _b.addInt(INT64_MIN); } else { @@ -221,7 +221,7 @@ void Parser::parseString () { if (remainder >= 16) { _b.reserveSpace(remainder); size_t count; - if (options.validateUtf8Strings) { + if (options->validateUtf8Strings) { count = JSONStringCopyCheckUtf8(_b._start + _b._pos, _start + _pos, remainder); } @@ -370,7 +370,7 @@ void Parser::parseString () { _b._start[_b._pos++] = static_cast(i); } else { - if (! options.validateUtf8Strings) { + if (! options->validateUtf8Strings) { highSurrogate = 0; _b.reserveSpace(1); _b._start[_b._pos++] = static_cast(i); @@ -460,7 +460,7 @@ void Parser::parseObject () { if (i == '}') { // empty object consume(); // the closing ']' - if (_nesting != 0 || ! options.keepTopLevelOpen) { + if (_nesting != 0 || ! options->keepTopLevelOpen) { // only close if we've not been asked to keep top level open _b.close(); } @@ -479,13 +479,13 @@ void Parser::parseObject () { _b.reportAdd(base); bool excludeAttribute = false; - if (options.attributeExcludeHandler == nullptr) { + if (options->attributeExcludeHandler == nullptr) { parseString(); } else { auto lastPos = _b._pos; parseString(); - if (options.attributeExcludeHandler->shouldExclude(Slice(_b._start + lastPos, options.customTypeHandler), _nesting)) { + if (options->attributeExcludeHandler->shouldExclude(Slice(_b._start + lastPos, options), _nesting)) { excludeAttribute = true; } } @@ -506,7 +506,7 @@ void Parser::parseObject () { if (i == '}') { // end of object ++_pos; // the closing '}' - if (_nesting != 1 || ! options.keepTopLevelOpen) { + if (_nesting != 1 || ! options->keepTopLevelOpen) { // only close if we've not been asked to keep top level open _b.close(); } diff --git a/3rdParty/velocypack/src/Slice.cpp b/3rdParty/velocypack/src/Slice.cpp index ee1ebf3ba6..b7308058e9 100644 --- a/3rdParty/velocypack/src/Slice.cpp +++ b/3rdParty/velocypack/src/Slice.cpp @@ -39,8 +39,8 @@ VT const Slice::TypeMap[256] = { /* 0x04 */ VT::Array, /* 0x05 */ VT::Array, /* 0x06 */ VT::Array, /* 0x07 */ VT::Array, /* 0x08 */ VT::Array, /* 0x09 */ VT::Array, /* 0x0a */ VT::Object, /* 0x0b */ VT::Object, /* 0x0c */ VT::Object, /* 0x0d */ VT::Object, /* 0x0e */ VT::Object, /* 0x0f */ VT::Object, - /* 0x10 */ VT::Object, /* 0x11 */ VT::Object, /* 0x12 */ VT::Object, /* 0x13 */ VT::None, - /* 0x14 */ VT::None, /* 0x15 */ VT::None, /* 0x16 */ VT::None, /* 0x17 */ VT::None, + /* 0x10 */ VT::Object, /* 0x11 */ VT::Object, /* 0x12 */ VT::Object, /* 0x13 */ VT::Array, + /* 0x14 */ VT::Object, /* 0x15 */ VT::None, /* 0x16 */ VT::None, /* 0x17 */ VT::None, /* 0x18 */ VT::Null, /* 0x19 */ VT::Bool, /* 0x1a */ VT::Bool, /* 0x1b */ VT::Double, /* 0x1c */ VT::UTCDate, /* 0x1d */ VT::External, /* 0x1e */ VT::MinKey, /* 0x1f */ VT::MaxKey, /* 0x20 */ VT::Int, /* 0x21 */ VT::Int, /* 0x22 */ VT::Int, /* 0x23 */ VT::Int, @@ -101,7 +101,7 @@ VT const Slice::TypeMap[256] = { /* 0xfc */ VT::Custom, /* 0xfd */ VT::Custom, /* 0xfe */ VT::Custom, /* 0xff */ VT::Custom }; -unsigned int const Slice::WidthMap[256] = { +unsigned int const Slice::WidthMap[32] = { 0, // 0x00, None 1, // 0x01, empty array 1, // 0x02, array without index table @@ -124,7 +124,7 @@ unsigned int const Slice::WidthMap[256] = { 0 }; -unsigned int const Slice::FirstSubMap[256] = { +unsigned int const Slice::FirstSubMap[32] = { 0, // 0x00, None 1, // 0x01, empty array 2, // 0x02, array without index table @@ -148,27 +148,383 @@ unsigned int const Slice::FirstSubMap[256] = { }; std::string Slice::toJson () const { - Options options; - options.customTypeHandler = customTypeHandler; - - StringSink sink; + std::string buffer; + StringSink sink(&buffer); Dumper dumper(&sink, options); dumper.dump(this); - return std::move(sink.buffer); + return std::move(buffer); } std::string Slice::toString () const { - Options options; - options.prettyPrint = true; + // copy options and set prettyPrint in copy + Options prettyOptions = *options; + prettyOptions.prettyPrint = true; - StringSink sink; - Dumper::dump(this, &sink, options); - return std::move(sink.buffer); + std::string buffer; + StringSink sink(&buffer); + Dumper::dump(this, &sink, &prettyOptions); + return std::move(buffer); } std::string Slice::hexType () const { return std::move(HexDump::toHex(head())); } + +// look for the specified attribute inside an Object +// returns a Slice(ValueType::None) if not found +Slice Slice::get (std::string const& attribute) const { + if (! isType(ValueType::Object)) { + throw Exception(Exception::InvalidValueType, "Expecting Object"); + } + + auto const h = head(); + if (h == 0x0a) { + // special case, empty object + return Slice(); + } + + if (h == 0x14) { + // compact Object + return getFromCompactObject(attribute); + } + + ValueLength const offsetSize = indexEntrySize(h); + ValueLength end = readInteger(_start + 1, offsetSize); + ValueLength dataOffset = 0; + + // read number of items + ValueLength n; + if (h <= 0x05) { // No offset table or length, need to compute: + dataOffset = findDataOffset(h); + Slice first(_start + dataOffset, options); + n = (end - dataOffset) / first.byteSize(); + } + else if (offsetSize < 8) { + n = readInteger(_start + 1 + offsetSize, offsetSize); + } + else { + n = readInteger(_start + end - offsetSize, offsetSize); + } + + if (n == 1) { + // Just one attribute, there is no index table! + if (dataOffset == 0) { + dataOffset = findDataOffset(h); + } + + Slice key = Slice(_start + dataOffset, options); + if (! key.isString()) { + return Slice(); + } + if (! key.isEqualString(attribute)) { + return Slice(); + } + + return Slice(key.start() + key.byteSize(), options); + } + + ValueLength const ieBase = end - n * offsetSize + - (offsetSize == 8 ? offsetSize : 0); + + // only use binary search for attributes if we have at least this many entries + // otherwise we'll always use the linear search + static ValueLength const SortedSearchEntriesThreshold = 4; + + if (isSorted() && n >= SortedSearchEntriesThreshold) { + // This means, we have to handle the special case n == 1 only + // in the linear search! + return searchObjectKeyBinary(attribute, ieBase, offsetSize, n); + } + + return searchObjectKeyLinear(attribute, ieBase, offsetSize, n); +} + +// return the value for an Int object +int64_t Slice::getInt () const { + uint8_t const h = head(); + if (h >= 0x20 && h <= 0x27) { + // Int T + uint64_t v = readInteger(_start + 1, h - 0x1f); + if (h == 0x27) { + return toInt64(v); + } + else { + int64_t vv = static_cast(v); + int64_t shift = 1LL << ((h - 0x1f) * 8 - 1); + return vv < shift ? vv : vv - (shift << 1); + } + } + + if (h >= 0x28 && h <= 0x2f) { + // UInt + uint64_t v = getUInt(); + if (v > static_cast(INT64_MAX)) { + throw Exception(Exception::NumberOutOfRange); + } + return static_cast(v); + } + + if (h >= 0x30 && h <= 0x3f) { + // SmallInt + return getSmallInt(); + } + + throw Exception(Exception::InvalidValueType, "Expecting type Int"); +} + +// return the value for a UInt object +uint64_t Slice::getUInt () const { + uint8_t const h = head(); + if (h >= 0x28 && h <= 0x2f) { + // UInt + return readInteger(_start + 1, h - 0x27); + } + + if (h >= 0x20 && h <= 0x27) { + // Int + int64_t v = getInt(); + if (v < 0) { + throw Exception(Exception::NumberOutOfRange); + } + return static_cast(v); + } + + if (h >= 0x30 && h <= 0x39) { + // Smallint >= 0 + return static_cast(h - 0x30); + } + + if (h >= 0x3a && h <= 0x3f) { + // Smallint < 0 + throw Exception(Exception::NumberOutOfRange); + } + + throw Exception(Exception::InvalidValueType, "Expecting type UInt"); +} + +// return the value for a SmallInt object +int64_t Slice::getSmallInt () const { + uint8_t const h = head(); + + if (h >= 0x30 && h <= 0x39) { + // Smallint >= 0 + return static_cast(h - 0x30); + } + + if (h >= 0x3a && h <= 0x3f) { + // Smallint < 0 + return static_cast(h - 0x3a) - 6; + } + + if ((h >= 0x20 && h <= 0x27) || + (h >= 0x28 && h <= 0x2f)) { + // Int and UInt + // we'll leave it to the compiler to detect the two ranges above are adjacent + return getInt(); + } + + throw Exception(Exception::InvalidValueType, "Expecting type Smallint"); +} + +int Slice::compareString (std::string const& attribute) const { + ValueLength keyLength; + char const* k = getString(keyLength); + size_t const attributeLength = attribute.size(); + size_t const compareLength = (std::min)(static_cast(keyLength), attributeLength); + int res = memcmp(k, attribute.c_str(), compareLength); + + if (res == 0) { + if (keyLength != attributeLength) { + return (keyLength > attributeLength) ? 1 : -1; + } + } + return res; +} + +bool Slice::isEqualString (std::string const& attribute) const { + ValueLength keyLength; + char const* k = getString(keyLength); + if (static_cast(keyLength) != attribute.size()) { + return false; + } + return (memcmp(k, attribute.c_str(), attribute.size()) == 0); +} + +Slice Slice::getFromCompactObject (std::string const& attribute) const { + ValueLength n = length(); + ValueLength current = 0; + + while (current != n) { + Slice key = keyAt(current); + if (key.isString()) { + if (key.isEqualString(attribute)) { + return Slice(key.start() + key.byteSize(), options); + } + } + ++current; + } + // not found + return Slice(); +} + +// get the offset for the nth member from an Array or Object type +ValueLength Slice::getNthOffset (ValueLength index) const { + VELOCYPACK_ASSERT(type() == ValueType::Array || type() == ValueType::Object); + + auto const h = head(); + if (h == 0x01 || h == 0x0a) { + // special case. empty array or object + throw Exception(Exception::IndexOutOfBounds); + } + + if (h == 0x13 || h == 0x14) { + // compact Array or Object + return getNthOffsetFromCompact(index); + } + + ValueLength const offsetSize = indexEntrySize(h); + ValueLength end = readInteger(_start + 1, offsetSize); + + ValueLength dataOffset = findDataOffset(h); + + // find the number of items + ValueLength n; + if (h <= 0x05) { // No offset table or length, need to compute: + Slice first(_start + dataOffset, options); + n = (end - dataOffset) / first.byteSize(); + } + else if (offsetSize < 8) { + n = readInteger(_start + 1 + offsetSize, offsetSize); + } + else { + n = readInteger(_start + end - offsetSize, offsetSize); + } + + if (index >= n) { + throw Exception(Exception::IndexOutOfBounds); + } + + // empty array case was already covered + VELOCYPACK_ASSERT(n > 0); + + if (h <= 0x05 || n == 1) { + // no index table, but all array items have the same length + // now fetch first item and determine its length + if (dataOffset == 0) { + dataOffset = findDataOffset(h); + } + Slice firstItem(_start + dataOffset, options); + return dataOffset + index * firstItem.byteSize(); + } + + ValueLength const ieBase = end - n * offsetSize + index * offsetSize + - (offsetSize == 8 ? 8 : 0); + return readInteger(_start + ieBase, offsetSize); +} + +// extract the nth member from an Array or Object type +Slice Slice::getNth (ValueLength index) const { + VELOCYPACK_ASSERT(type() == ValueType::Array || type() == ValueType::Object); + + auto const h = head(); + if (h == 0x01 || h == 0x0a) { + // special case. empty array or object + throw Exception(Exception::IndexOutOfBounds); + } + + return Slice(_start + getNthOffset(index), options); +} + +// get the offset for the nth member from a compact Array or Object type +ValueLength Slice::getNthOffsetFromCompact (ValueLength index) const { + ValueLength end = readVariableValueLength(_start + 1); + ValueLength n = readVariableValueLength(_start + end - 1); + if (index >= n) { + throw Exception(Exception::IndexOutOfBounds); + } + + auto const h = head(); + ValueLength offset = 1 + getVariableValueLength(end); + ValueLength current = 0; + while (current != index) { + uint8_t const* s = _start + offset; + Slice key = Slice(s, options); + offset += key.byteSize(); + if (h == 0x14) { + Slice value = Slice(_start + offset, options); + offset += value.byteSize(); + } + ++current; + } + return offset; +} + +// perform a linear search for the specified attribute inside an Object +Slice Slice::searchObjectKeyLinear (std::string const& attribute, + ValueLength ieBase, + ValueLength offsetSize, + ValueLength n) const { + for (ValueLength index = 0; index < n; ++index) { + ValueLength offset = ieBase + index * offsetSize; + Slice key(_start + readInteger(_start + offset, offsetSize), options); + if (! key.isString()) { + // invalid object + return Slice(); + } + + if (! key.isEqualString(attribute)) { + continue; + } + // key is identical. now return value + return Slice(key.start() + key.byteSize(), options); + } + + // nothing found + return Slice(); +} + +// perform a binary search for the specified attribute inside an Object +Slice Slice::searchObjectKeyBinary (std::string const& attribute, + ValueLength ieBase, + ValueLength offsetSize, + ValueLength n) const { + VELOCYPACK_ASSERT(n > 0); + + ValueLength l = 0; + ValueLength r = n - 1; + + while (true) { + // midpoint + ValueLength index = l + ((r - l) / 2); + + ValueLength offset = ieBase + index * offsetSize; + Slice key(_start + readInteger(_start + offset, offsetSize), options); + if (! key.isString()) { + // invalid object + return Slice(); + } + + int res = key.compareString(attribute); + + if (res == 0) { + // found + return Slice(key.start() + key.byteSize(), options); + } + + if (res > 0) { + if (index == 0) { + return Slice(); + } + r = index - 1; + } + else { + l = index + 1; + } + if (r < l) { + return Slice(); + } + } +} std::ostream& operator<< (std::ostream& stream, Slice const* slice) { stream << "[Slice " << valueTypeName(slice->type()) << " (" << slice->hexType() << "), byteSize: " << slice->byteSize() << "]"; diff --git a/3rdParty/velocypack/src/asm-functions.cpp b/3rdParty/velocypack/src/asm-functions.cpp index 6cee5574b3..d0cde058ba 100644 --- a/3rdParty/velocypack/src/asm-functions.cpp +++ b/3rdParty/velocypack/src/asm-functions.cpp @@ -65,15 +65,16 @@ static bool HasSSE42 () { static size_t JSONStringCopySSE42 (uint8_t* dst, uint8_t const* src, size_t limit) { alignas(16) static char const ranges[17] - = "\x00\x1f\"\"\\\\\"\"\"\"\"\"\"\"\"\""; + = "\x20\x21\x23\x5b\x5d\xff "; + //= "\x01\x1f\"\"\\\\\"\"\"\"\"\"\"\"\"\""; __m128i const r = _mm_load_si128(reinterpret_cast<__m128i const*>(ranges)); size_t count = 0; int x = 0; while (limit >= 16) { __m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(src)); - x = _mm_cmpestri(r, 6, s, 16, + x = _mm_cmpistri(r, /* 6, */ s, /* 16, */ _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | - _SIDD_POSITIVE_POLARITY | + _SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT); if (x < 16) { memcpy(dst, src, x); @@ -92,9 +93,9 @@ static size_t JSONStringCopySSE42 (uint8_t* dst, uint8_t const* src, size_t limi return count; } __m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(src)); - x = _mm_cmpestri(r, 6, s, limit, + x = _mm_cmpistri(r, /* 6, */ s, /* limit, */ _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | - _SIDD_POSITIVE_POLARITY | + _SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT); if (x > static_cast(limit)) { x = static_cast(limit); @@ -119,15 +120,17 @@ static size_t DoInitCopy (uint8_t* dst, uint8_t const* src, size_t limit) { static size_t JSONStringCopyCheckUtf8SSE42 (uint8_t* dst, uint8_t const* src, size_t limit) { - alignas(16) static unsigned char const ranges[17] = "\x00\x1f\x80\xff\"\"\\\\\"\"\"\"\"\"\"\""; + alignas(16) static unsigned char const ranges[17] + = "\x20\x21\x23\x5b\x5d\x7f "; + //= "\x01\x1f\x80\xff\"\"\\\\\"\"\"\"\"\"\"\""; __m128i const r = _mm_load_si128(reinterpret_cast<__m128i const*>(ranges)); size_t count = 0; int x = 0; while (limit >= 16) { __m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(src)); - x = _mm_cmpestri(r, 8, s, 16, + x = _mm_cmpistri(r, /* 8, */ s, /* 16, */ _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | - _SIDD_POSITIVE_POLARITY | + _SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT); if (x < 16) { memcpy(dst, src, x); @@ -146,9 +149,9 @@ static size_t JSONStringCopyCheckUtf8SSE42 (uint8_t* dst, return count; } __m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(src)); - x = _mm_cmpestri(r, 8, s, limit, + x = _mm_cmpistri(r, /* 8, */ s, /* limit, */ _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | - _SIDD_POSITIVE_POLARITY | + _SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT); if (x > static_cast(limit)) { x = static_cast(limit); @@ -296,7 +299,7 @@ void TestStringCopyCorrectness (uint8_t* src, uint8_t* dst, size_t size) { src[pos] = merk; // Test a 0 character: - src[pos] = 0; + src[pos] = 1; copied = JSONStringCopy(dst, src, size); if (copied != pos || memcmp(dst, src, copied) != 0) { std::cout << "Error: " << salign << " " << dalign << " " @@ -371,7 +374,7 @@ void TestStringCopyCorrectnessCheckUtf8 (uint8_t* src, uint8_t* dst, src[pos] = merk; // Test a 0 character: - src[pos] = 0; + src[pos] = 1; copied = JSONStringCopyCheckUtf8(dst, src, size); if (copied != pos || memcmp(dst, src, copied) != 0) { std::cout << "Error: " << salign << " " << dalign << " " diff --git a/3rdParty/velocypack/src/velocypack-common.cpp b/3rdParty/velocypack/src/velocypack-common.cpp index d56a0fcf6a..e9e453b88e 100644 --- a/3rdParty/velocypack/src/velocypack-common.cpp +++ b/3rdParty/velocypack/src/velocypack-common.cpp @@ -33,14 +33,14 @@ using namespace arangodb::velocypack; #ifndef VELOCYPACK_64BIT // check if the length is beyond the size of a SIZE_MAX on this platform -void CheckValueLength (ValueLength length) { +void checkValueLength (ValueLength length) { if (length > static_cast(SIZE_MAX)) { throw Exception(Exception::NumberOutOfRange); } } #endif -int64_t arangodb::velocypack::CurrentUTCDateValue () { +int64_t arangodb::velocypack::currentUTCDateValue () { return static_cast(std::chrono::system_clock::now().time_since_epoch().count() / std::chrono::milliseconds(1).count()); } diff --git a/lib/Basics/VelocyPackHelper.cpp b/lib/Basics/VelocyPackHelper.cpp index 276c8dd3c7..b40431054d 100644 --- a/lib/Basics/VelocyPackHelper.cpp +++ b/lib/Basics/VelocyPackHelper.cpp @@ -75,10 +75,7 @@ std::string VelocyPackHelper::checkAndGetStringValue (VPackSlice const& slice, } TRI_json_t* VelocyPackHelper::velocyPackToJson (VPackSlice const& slice) { - VPackStringSink sink; - VPackDumper dumper(&sink); - dumper.dump(slice); - return JsonHelper::fromString(sink.buffer); + return JsonHelper::fromString(slice.toJson()); } // ----------------------------------------------------------------------------- diff --git a/lib/Rest/HttpRequest.cpp b/lib/Rest/HttpRequest.cpp index 5f080dac7a..cccc1bc5ea 100644 --- a/lib/Rest/HttpRequest.cpp +++ b/lib/Rest/HttpRequest.cpp @@ -519,14 +519,14 @@ void HttpRequest::setHeader (char const* key, //////////////////////////////////////////////////////////////////////////////// VPackBuilder HttpRequest::toVelocyPack () { - VPackParser parser; - parser.options.checkAttributeUniqueness = true; + VPackOptions options; + options.checkAttributeUniqueness = true; + + VPackParser parser(&options); parser.parse(body()); return parser.steal(); } - - //////////////////////////////////////////////////////////////////////////////// /// @brief gets the request body as TRI_json_t* ////////////////////////////////////////////////////////////////////////////////