mirror of https://gitee.com/bigwinds/arangodb
updated vpack library
This commit is contained in:
parent
e54527a037
commit
dca8efa82f
|
@ -27,11 +27,11 @@
|
|||
#ifndef VELOCYPACK_BUILDER_H
|
||||
#define VELOCYPACK_BUILDER_H
|
||||
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "velocypack/velocypack-common.h"
|
||||
#include "velocypack/Buffer.h"
|
||||
|
@ -62,7 +62,7 @@ namespace arangodb {
|
|||
|
||||
private:
|
||||
|
||||
Buffer<uint8_t> _buffer; // Here we collect the result
|
||||
std::shared_ptr<Buffer<uint8_t>> _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<uint8_t>>& 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<uint8_t>()),
|
||||
_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<Buffer<uint8_t>> const& buffer () const {
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
// get a non-const reference to the Builder's Buffer object
|
||||
std::shared_ptr<Buffer<uint8_t>>& 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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -42,26 +42,46 @@ 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 {
|
||||
|
@ -69,6 +89,9 @@ namespace arangodb {
|
|||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<uint8_t const*>(json.c_str());
|
||||
_size = json.size();
|
||||
_pos = 0;
|
||||
_b.clear();
|
||||
_b.options = options;
|
||||
return parseInternal(multi);
|
||||
return parse(reinterpret_cast<uint8_t const*>(json.c_str()), json.size(), multi);
|
||||
}
|
||||
|
||||
ValueLength parse (char const* start, size_t size,
|
||||
bool multi = false) {
|
||||
return parse(reinterpret_cast<uint8_t const*>(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<uint8_t const*>(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);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#define VELOCYPACK_SINK_H 1
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "velocypack/velocypack-common.h"
|
||||
#include "velocypack/Buffer.h"
|
||||
|
@ -51,71 +53,70 @@ namespace arangodb {
|
|||
};
|
||||
|
||||
template<typename T>
|
||||
struct ByteBufferSink final : public Sink {
|
||||
ByteBufferSink ()
|
||||
: buffer() {
|
||||
}
|
||||
|
||||
ByteBufferSink (ValueLength size)
|
||||
: buffer(size) {
|
||||
struct ByteBufferSinkImpl final : public Sink {
|
||||
explicit ByteBufferSinkImpl (Buffer<T>* 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.c_str(), p.size());
|
||||
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);
|
||||
}
|
||||
|
||||
Buffer<T> buffer;
|
||||
Buffer<T>* buffer;
|
||||
};
|
||||
|
||||
struct StringSink final : public Sink {
|
||||
StringSink ()
|
||||
: 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);
|
||||
}
|
||||
|
||||
std::string buffer;
|
||||
};
|
||||
|
||||
typedef ByteBufferSink<char> CharBufferSink;
|
||||
typedef ByteBufferSinkImpl<char> CharBufferSink;
|
||||
|
||||
template<typename T>
|
||||
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<std::string> StringSink;
|
||||
|
||||
template<typename T>
|
||||
struct StreamSinkImpl final : public Sink {
|
||||
explicit StreamSinkImpl (T* stream)
|
||||
: stream(stream) {
|
||||
}
|
||||
|
||||
|
@ -141,6 +142,9 @@ namespace arangodb {
|
|||
T* stream;
|
||||
};
|
||||
|
||||
typedef StreamSinkImpl<std::ostringstream> StringStreamSink;
|
||||
typedef StreamSinkImpl<std::ofstream> OutputFileStreamSink;
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
|
|
|
@ -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<uint8_t const*>(start)), customTypeHandler(handler) {
|
||||
explicit Slice (char const* start, Options const* options = &Options::Defaults)
|
||||
: _start(reinterpret_cast<uint8_t const*>(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<false>(_start + 1);
|
||||
return readVariableValueLength<true>(_start + end - 1);
|
||||
}
|
||||
|
||||
ValueLength const offsetSize = indexEntrySize(h);
|
||||
ValueLength end = readInteger<ValueLength>(_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<ValueLength>(_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<ValueLength>(_start + 1 + offsetSize, offsetSize);
|
||||
}
|
||||
else {
|
||||
n = readInteger<ValueLength>(_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<ValueLength>(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<uint64_t>(_start + 1, h - 0x1f);
|
||||
if (h == 0x27) {
|
||||
return ToInt64(v);
|
||||
}
|
||||
else {
|
||||
int64_t vv = static_cast<int64_t>(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<uint64_t>(INT64_MAX)) {
|
||||
throw Exception(Exception::NumberOutOfRange);
|
||||
}
|
||||
return static_cast<int64_t>(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<uint64_t>(_start + 1, h - 0x27);
|
||||
}
|
||||
|
||||
if (h >= 0x20 && h <= 0x27) {
|
||||
// Int
|
||||
int64_t v = getInt();
|
||||
if (v < 0) {
|
||||
throw Exception(Exception::NumberOutOfRange);
|
||||
}
|
||||
return static_cast<int64_t>(v);
|
||||
}
|
||||
|
||||
if (h >= 0x30 && h <= 0x39) {
|
||||
// Smallint >= 0
|
||||
return static_cast<uint64_t>(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<int64_t>(h - 0x30);
|
||||
}
|
||||
|
||||
if (h >= 0x3a && h <= 0x3f) {
|
||||
// Smallint < 0
|
||||
return static_cast<int64_t>(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<typename T>
|
||||
T getNumericValue () const {
|
||||
|
@ -596,7 +475,7 @@ namespace arangodb {
|
|||
int64_t getUTCDate () const {
|
||||
assertType(ValueType::UTCDate);
|
||||
uint64_t v = readInteger<uint64_t>(_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<ValueLength>(_start + 1, 8);
|
||||
CheckValueLength(length);
|
||||
checkValueLength(length);
|
||||
return reinterpret_cast<char const*>(_start + 1 + 8);
|
||||
}
|
||||
|
||||
|
@ -629,7 +508,7 @@ namespace arangodb {
|
|||
|
||||
if (h == 0xbf) {
|
||||
ValueLength length = readInteger<ValueLength>(_start + 1, 8);
|
||||
CheckValueLength(length);
|
||||
checkValueLength(length);
|
||||
return std::string(reinterpret_cast<char const*>(_start + 1 + 8), length);
|
||||
}
|
||||
|
||||
|
@ -643,7 +522,7 @@ namespace arangodb {
|
|||
|
||||
if (h >= 0xc0 && h <= 0xc7) {
|
||||
length = readInteger<ValueLength>(_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<uint8_t> out;
|
||||
ValueLength length = readInteger<ValueLength>(_start + 1, h - 0xbf);
|
||||
CheckValueLength(length);
|
||||
checkValueLength(length);
|
||||
out.reserve(static_cast<size_t>(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<false>(_start + 1);
|
||||
}
|
||||
|
||||
VELOCYPACK_ASSERT(h <= 0x12);
|
||||
return readInteger<ValueLength>(_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;
|
||||
|
@ -771,138 +663,39 @@ namespace arangodb {
|
|||
return 9;
|
||||
}
|
||||
|
||||
// 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 valueOffset (ValueLength index) const {
|
||||
if (type() != ValueType::Array && type() != ValueType::Object) {
|
||||
throw Exception(Exception::InvalidValueType, "Expecting Array or Object");
|
||||
}
|
||||
|
||||
ValueLength const offsetSize = indexEntrySize(h);
|
||||
ValueLength end = readInteger<ValueLength>(_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<ValueLength>(_start + 1 + offsetSize, offsetSize);
|
||||
}
|
||||
else {
|
||||
n = readInteger<ValueLength>(_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<ValueLength>(_start + ieBase, offsetSize), customTypeHandler);
|
||||
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;
|
||||
|
||||
// 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<ValueLength>(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<ValueLength>(_start + offset, offsetSize), customTypeHandler);
|
||||
if (! key.isString()) {
|
||||
// invalid object
|
||||
return Slice();
|
||||
}
|
||||
|
||||
ValueLength keyLength;
|
||||
char const* k = key.getString(keyLength);
|
||||
if (keyLength != static_cast<ValueLength>(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<ValueLength>(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<ValueLength>(_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<size_t>((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
|
||||
|
|
|
@ -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<int64_t>(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<uint64_t>(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<uint64_t>(i);
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<bool reverse>
|
||||
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<bool reverse>
|
||||
static inline void storeVariableValueLength (uint8_t* dst, ValueLength value) {
|
||||
VELOCYPACK_ASSERT(value > 0);
|
||||
|
||||
if (reverse) {
|
||||
while (value >= 0x80) {
|
||||
*dst-- = static_cast<uint8_t>(value | 0x80);
|
||||
value >>= 7;
|
||||
}
|
||||
*dst-- = static_cast<uint8_t>(value & 0x7f);
|
||||
}
|
||||
else {
|
||||
while (value >= 0x80) {
|
||||
*dst++ = static_cast<uint8_t>(value | 0x80);
|
||||
value >>= 7;
|
||||
}
|
||||
*dst++ = static_cast<uint8_t>(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<int64_t>(shift2 - 1);
|
||||
return v >= shift2 ? (static_cast<int64_t>(v - shift2) - shift) - 1
|
||||
|
|
|
@ -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<ValueLength>& 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<ValueLength>(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<false>(_start + tos + 1, byteSize);
|
||||
|
||||
// need additional memory for storing the number of values
|
||||
if (nLen > 8 - bLen) {
|
||||
reserveSpace(nLen);
|
||||
}
|
||||
storeVariableValueLength<true>(_start + tos + byteSize - 1, static_cast<ValueLength>(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<ValueLength> 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()) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ void Parser::parseNumber () {
|
|||
if (numberValue.intValue <= static_cast<uint64_t>(INT64_MAX)) {
|
||||
_b.addInt(-static_cast<int64_t>(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<uint8_t>(i);
|
||||
}
|
||||
else {
|
||||
if (! options.validateUtf8Strings) {
|
||||
if (! options->validateUtf8Strings) {
|
||||
highSurrogate = 0;
|
||||
_b.reserveSpace(1);
|
||||
_b._start[_b._pos++] = static_cast<uint8_t>(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();
|
||||
}
|
||||
|
|
|
@ -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,28 +148,384 @@ 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<ValueLength>(_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<ValueLength>(_start + 1 + offsetSize, offsetSize);
|
||||
}
|
||||
else {
|
||||
n = readInteger<ValueLength>(_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<uint64_t>(_start + 1, h - 0x1f);
|
||||
if (h == 0x27) {
|
||||
return toInt64(v);
|
||||
}
|
||||
else {
|
||||
int64_t vv = static_cast<int64_t>(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<uint64_t>(INT64_MAX)) {
|
||||
throw Exception(Exception::NumberOutOfRange);
|
||||
}
|
||||
return static_cast<int64_t>(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<uint64_t>(_start + 1, h - 0x27);
|
||||
}
|
||||
|
||||
if (h >= 0x20 && h <= 0x27) {
|
||||
// Int
|
||||
int64_t v = getInt();
|
||||
if (v < 0) {
|
||||
throw Exception(Exception::NumberOutOfRange);
|
||||
}
|
||||
return static_cast<int64_t>(v);
|
||||
}
|
||||
|
||||
if (h >= 0x30 && h <= 0x39) {
|
||||
// Smallint >= 0
|
||||
return static_cast<uint64_t>(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<int64_t>(h - 0x30);
|
||||
}
|
||||
|
||||
if (h >= 0x3a && h <= 0x3f) {
|
||||
// Smallint < 0
|
||||
return static_cast<int64_t>(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<size_t>(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<size_t>(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<ValueLength>(_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<ValueLength>(_start + 1 + offsetSize, offsetSize);
|
||||
}
|
||||
else {
|
||||
n = readInteger<ValueLength>(_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<ValueLength>(_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<false>(_start + 1);
|
||||
ValueLength n = readVariableValueLength<true>(_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<ValueLength>(_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<ValueLength>(_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() << "]";
|
||||
return stream;
|
||||
|
|
|
@ -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<int>(limit)) {
|
||||
x = static_cast<int>(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<int>(limit)) {
|
||||
x = static_cast<int>(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 << " "
|
||||
|
|
|
@ -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<ValueLength>(SIZE_MAX)) {
|
||||
throw Exception(Exception::NumberOutOfRange);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int64_t arangodb::velocypack::CurrentUTCDateValue () {
|
||||
int64_t arangodb::velocypack::currentUTCDateValue () {
|
||||
return static_cast<int64_t>(std::chrono::system_clock::now().time_since_epoch().count() / std::chrono::milliseconds(1).count());
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -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*
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Reference in New Issue