mirror of https://gitee.com/bigwinds/arangodb
updated vpack library
This commit is contained in:
parent
e4a3c462c7
commit
d24b46bb71
|
@ -35,53 +35,43 @@
|
|||
#include "velocypack/velocypack-common.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
class Builder;
|
||||
namespace velocypack {
|
||||
class Builder;
|
||||
|
||||
class AttributeTranslator {
|
||||
class AttributeTranslator {
|
||||
public:
|
||||
AttributeTranslator(AttributeTranslator const&) = delete;
|
||||
AttributeTranslator& operator=(AttributeTranslator const&) = delete;
|
||||
|
||||
public:
|
||||
AttributeTranslator() : _builder(), _count(0) {}
|
||||
|
||||
AttributeTranslator (AttributeTranslator const&) = delete;
|
||||
AttributeTranslator& operator= (AttributeTranslator const&) = delete;
|
||||
~AttributeTranslator() {}
|
||||
|
||||
AttributeTranslator ()
|
||||
: _builder(), _count(0) {
|
||||
}
|
||||
size_t count() const { return _count; }
|
||||
|
||||
~AttributeTranslator () {
|
||||
}
|
||||
void add(std::string const& key, uint64_t id);
|
||||
|
||||
size_t count () const {
|
||||
return _count;
|
||||
}
|
||||
void seal();
|
||||
|
||||
void add (std::string const& key, uint64_t id);
|
||||
Builder* builder() { return _builder.get(); }
|
||||
|
||||
void seal ();
|
||||
// translate from string to id
|
||||
uint8_t const* translate(std::string const& key) const;
|
||||
|
||||
Builder* builder () {
|
||||
return _builder.get();
|
||||
}
|
||||
// translate from string to id
|
||||
uint8_t const* translate(char const* key, ValueLength length) const;
|
||||
|
||||
// translate from string to id
|
||||
uint8_t const* translate (std::string const& key) const;
|
||||
// translate from id to string
|
||||
uint8_t const* translate(uint64_t id) const;
|
||||
|
||||
// translate from string to id
|
||||
uint8_t const* translate (char const* key, ValueLength length) const;
|
||||
private:
|
||||
std::unique_ptr<Builder> _builder;
|
||||
std::unordered_map<std::string, uint8_t const*> _keyToId;
|
||||
std::unordered_map<uint64_t, uint8_t const*> _idToKey;
|
||||
size_t _count;
|
||||
};
|
||||
|
||||
// translate from id to string
|
||||
uint8_t const* translate (uint64_t id) const;
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<Builder> _builder;
|
||||
std::unordered_map<std::string, uint8_t const*> _keyToId;
|
||||
std::unordered_map<uint64_t, uint8_t const*> _idToKey;
|
||||
size_t _count;
|
||||
};
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,190 +33,162 @@
|
|||
#include "velocypack/velocypack-common.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
namespace velocypack {
|
||||
|
||||
template<typename T>
|
||||
class Buffer {
|
||||
|
||||
public:
|
||||
|
||||
Buffer ()
|
||||
: _buffer(_local),
|
||||
_alloc(sizeof(_local)),
|
||||
_pos(0) {
|
||||
template <typename T>
|
||||
class Buffer {
|
||||
public:
|
||||
Buffer() : _buffer(_local), _alloc(sizeof(_local)), _pos(0) {
|
||||
#ifdef VELOCYPACK_DEBUG
|
||||
// poison memory
|
||||
memset(_buffer, 0xa5, _alloc);
|
||||
// poison memory
|
||||
memset(_buffer, 0xa5, _alloc);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
explicit Buffer (ValueLength expectedLength)
|
||||
: Buffer() {
|
||||
reserve(expectedLength);
|
||||
}
|
||||
explicit Buffer(ValueLength expectedLength) : Buffer() {
|
||||
reserve(expectedLength);
|
||||
}
|
||||
|
||||
Buffer (Buffer const& that)
|
||||
: Buffer() {
|
||||
|
||||
if (that._pos > 0) {
|
||||
if (that._pos > sizeof(_local)) {
|
||||
_buffer = new T[that._pos];
|
||||
}
|
||||
memcpy(_buffer, that._buffer, that._pos);
|
||||
_alloc = that._pos;
|
||||
_pos = that._pos;
|
||||
}
|
||||
}
|
||||
|
||||
Buffer& operator= (Buffer const& that) {
|
||||
if (this != &that) {
|
||||
reset();
|
||||
Buffer(Buffer const& that) : Buffer() {
|
||||
if (that._pos > 0) {
|
||||
if (that._pos > sizeof(_local)) {
|
||||
_buffer = new T[that._pos];
|
||||
}
|
||||
memcpy(_buffer, that._buffer, that._pos);
|
||||
_alloc = that._pos;
|
||||
_pos = that._pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (that._pos > 0) {
|
||||
if (that._pos > sizeof(_local)) {
|
||||
_buffer = new T[that._pos];
|
||||
}
|
||||
memcpy(_buffer, that._buffer, that._pos);
|
||||
_alloc = that._pos;
|
||||
_pos = that._pos;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
Buffer& operator=(Buffer const& that) {
|
||||
if (this != &that) {
|
||||
reset();
|
||||
|
||||
Buffer (Buffer&& that)
|
||||
: Buffer() {
|
||||
|
||||
if (that._buffer == that._local) {
|
||||
memcpy(_buffer, that._buffer, that._pos);
|
||||
_pos = that._pos;
|
||||
that._pos = 0;
|
||||
}
|
||||
else {
|
||||
_buffer = that._buffer;
|
||||
_alloc = that._alloc;
|
||||
_pos = that._pos;
|
||||
that._buffer = that._local;
|
||||
that._alloc = sizeof(that._local);
|
||||
that._pos = 0;
|
||||
}
|
||||
if (that._pos > 0) {
|
||||
if (that._pos > sizeof(_local)) {
|
||||
_buffer = new T[that._pos];
|
||||
}
|
||||
memcpy(_buffer, that._buffer, that._pos);
|
||||
_alloc = that._pos;
|
||||
_pos = that._pos;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Buffer () {
|
||||
reset();
|
||||
}
|
||||
Buffer(Buffer&& that) : Buffer() {
|
||||
if (that._buffer == that._local) {
|
||||
memcpy(_buffer, that._buffer, that._pos);
|
||||
_pos = that._pos;
|
||||
that._pos = 0;
|
||||
} else {
|
||||
_buffer = that._buffer;
|
||||
_alloc = that._alloc;
|
||||
_pos = that._pos;
|
||||
that._buffer = that._local;
|
||||
that._alloc = sizeof(that._local);
|
||||
that._pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline T* data () {
|
||||
return _buffer;
|
||||
}
|
||||
~Buffer() { reset(); }
|
||||
|
||||
inline T const* data () const {
|
||||
return _buffer;
|
||||
}
|
||||
inline T* data() { return _buffer; }
|
||||
|
||||
inline ValueLength size () const {
|
||||
return _pos;
|
||||
}
|
||||
|
||||
inline ValueLength length () const {
|
||||
return _pos;
|
||||
}
|
||||
inline T const* data() const { return _buffer; }
|
||||
|
||||
std::string toString () const {
|
||||
std::string result(reinterpret_cast<char const*>(_buffer), _pos);
|
||||
return std::move(result);
|
||||
}
|
||||
inline ValueLength size() const { return _pos; }
|
||||
|
||||
void clear () {
|
||||
reset();
|
||||
}
|
||||
inline ValueLength length() const { return _pos; }
|
||||
|
||||
void reset () {
|
||||
if (_buffer != _local) {
|
||||
delete[] _buffer;
|
||||
_buffer = _local;
|
||||
_alloc = sizeof(_local);
|
||||
std::string toString() const {
|
||||
std::string result(reinterpret_cast<char const*>(_buffer), _pos);
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
void clear() { reset(); }
|
||||
|
||||
void reset() {
|
||||
if (_buffer != _local) {
|
||||
delete[] _buffer;
|
||||
_buffer = _local;
|
||||
_alloc = sizeof(_local);
|
||||
#ifdef VELOCYPACK_DEBUG
|
||||
// poison memory
|
||||
memset(_buffer, 0xa5, _alloc);
|
||||
// poison memory
|
||||
memset(_buffer, 0xa5, _alloc);
|
||||
#endif
|
||||
}
|
||||
_pos = 0;
|
||||
}
|
||||
}
|
||||
_pos = 0;
|
||||
}
|
||||
|
||||
inline void push_back (char c) {
|
||||
reserve(1);
|
||||
_buffer[_pos++] = c;
|
||||
}
|
||||
inline void push_back(char c) {
|
||||
reserve(1);
|
||||
_buffer[_pos++] = c;
|
||||
}
|
||||
|
||||
void append (char const* p, ValueLength len) {
|
||||
reserve(len);
|
||||
memcpy(_buffer + _pos, p, len);
|
||||
_pos += len;
|
||||
}
|
||||
|
||||
void reserve (ValueLength len) {
|
||||
if (_pos + len < _alloc) {
|
||||
return;
|
||||
}
|
||||
void append(char const* p, ValueLength len) {
|
||||
reserve(len);
|
||||
memcpy(_buffer + _pos, p, len);
|
||||
_pos += len;
|
||||
}
|
||||
|
||||
VELOCYPACK_ASSERT(_pos + len >= sizeof(_local));
|
||||
void reserve(ValueLength len) {
|
||||
if (_pos + len < _alloc) {
|
||||
return;
|
||||
}
|
||||
|
||||
static ValueLength const MinLength = sizeof(_local);
|
||||
VELOCYPACK_ASSERT(_pos + len >= sizeof(_local));
|
||||
|
||||
// need reallocation
|
||||
ValueLength newLen = _pos + len;
|
||||
if (newLen < MinLength) {
|
||||
// ensure we don't alloc too small blocks
|
||||
newLen = MinLength;
|
||||
}
|
||||
static double const GrowthFactor = 1.25;
|
||||
if (_pos > 0 && newLen < GrowthFactor * _pos) {
|
||||
// ensure the buffer grows sensibly and not by 1 byte only
|
||||
newLen = static_cast<ValueLength>(GrowthFactor * _pos);
|
||||
}
|
||||
VELOCYPACK_ASSERT(newLen > _pos);
|
||||
static ValueLength const MinLength = sizeof(_local);
|
||||
|
||||
T* p = new T[newLen];
|
||||
// need reallocation
|
||||
ValueLength newLen = _pos + len;
|
||||
if (newLen < MinLength) {
|
||||
// ensure we don't alloc too small blocks
|
||||
newLen = MinLength;
|
||||
}
|
||||
static double const GrowthFactor = 1.25;
|
||||
if (_pos > 0 && newLen < GrowthFactor * _pos) {
|
||||
// ensure the buffer grows sensibly and not by 1 byte only
|
||||
newLen = static_cast<ValueLength>(GrowthFactor * _pos);
|
||||
}
|
||||
VELOCYPACK_ASSERT(newLen > _pos);
|
||||
|
||||
T* p = new T[newLen];
|
||||
#ifdef VELOCYPACK_DEBUG
|
||||
// poison memory
|
||||
memset(p, 0xa5, newLen);
|
||||
// poison memory
|
||||
memset(p, 0xa5, newLen);
|
||||
#endif
|
||||
// copy old data
|
||||
memcpy(p, _buffer, _pos);
|
||||
if (_buffer != _local) {
|
||||
delete[] _buffer;
|
||||
}
|
||||
_buffer = p;
|
||||
_alloc = newLen;
|
||||
}
|
||||
// copy old data
|
||||
memcpy(p, _buffer, _pos);
|
||||
if (_buffer != _local) {
|
||||
delete[] _buffer;
|
||||
}
|
||||
_buffer = p;
|
||||
_alloc = newLen;
|
||||
}
|
||||
|
||||
// reserve and zero fill
|
||||
void prealloc (ValueLength len) {
|
||||
reserve(len);
|
||||
// memset(_buffer + _pos, 0, len);
|
||||
_pos += len;
|
||||
}
|
||||
|
||||
private:
|
||||
// reserve and zero fill
|
||||
void prealloc(ValueLength len) {
|
||||
reserve(len);
|
||||
// memset(_buffer + _pos, 0, len);
|
||||
_pos += len;
|
||||
}
|
||||
|
||||
inline ValueLength capacity () const {
|
||||
return _alloc;
|
||||
}
|
||||
private:
|
||||
inline ValueLength capacity() const { return _alloc; }
|
||||
|
||||
|
||||
T* _buffer;
|
||||
ValueLength _alloc;
|
||||
ValueLength _pos;
|
||||
T* _buffer;
|
||||
ValueLength _alloc;
|
||||
ValueLength _pos;
|
||||
|
||||
// an already initialized space for small values
|
||||
T _local[192];
|
||||
// an already initialized space for small values
|
||||
T _local[192];
|
||||
};
|
||||
|
||||
};
|
||||
typedef Buffer<char> CharBuffer;
|
||||
|
||||
typedef Buffer<char> CharBuffer;
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,531 +43,551 @@
|
|||
#include "velocypack/ValueType.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
namespace velocypack {
|
||||
|
||||
class Builder {
|
||||
class Builder {
|
||||
friend class Parser; // The parser needs access to internals.
|
||||
|
||||
friend class Parser; // The parser needs access to internals.
|
||||
public:
|
||||
// A struct for sorting index tables for objects:
|
||||
struct SortEntry {
|
||||
uint8_t const* nameStart;
|
||||
uint64_t nameSize;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
public:
|
||||
// A struct for sorting index tables for objects:
|
||||
struct SortEntry {
|
||||
uint8_t const* nameStart;
|
||||
uint64_t nameSize;
|
||||
uint64_t offset;
|
||||
};
|
||||
void reserve(ValueLength len) { reserveSpace(len); }
|
||||
|
||||
void reserve (ValueLength len) {
|
||||
reserveSpace(len);
|
||||
}
|
||||
private:
|
||||
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
|
||||
std::vector<ValueLength> _stack; // Start positions of
|
||||
// open objects/arrays
|
||||
std::vector<std::vector<ValueLength>> _index; // Indices for starts
|
||||
// of subindex
|
||||
|
||||
private:
|
||||
// Here are the mechanics of how this building process works:
|
||||
// The whole VPack being built starts at where _start points to
|
||||
// and uses at most _size bytes. The variable _pos keeps the
|
||||
// current write position. The method "set" simply writes a new
|
||||
// VPack subobject at the current write position and advances
|
||||
// it. Whenever one makes an array or object, a ValueLength for
|
||||
// the beginning of the value is pushed onto the _stack, which
|
||||
// remembers that we are in the process of building an array or
|
||||
// object. The _index vectors are used to collect information
|
||||
// for the index tables of arrays and objects, which are written
|
||||
// behind the subvalues. The add methods are used to keep track
|
||||
// of the new subvalue in _index followed by a set, and are
|
||||
// what the user from the outside calls. The close method seals
|
||||
// the innermost array or object that is currently being built
|
||||
// and pops a ValueLength off the _stack. The vectors in _index
|
||||
// stay until the next clearTemporary() is called to minimize
|
||||
// allocations. In the beginning, the _stack is empty, which
|
||||
// allows to build a sequence of unrelated VPack objects in the
|
||||
// buffer. Whenever the stack is empty, one can use the start,
|
||||
// size and slice methods to get out the ready built VPack
|
||||
// object(s).
|
||||
|
||||
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
|
||||
std::vector<ValueLength> _stack; // Start positions of
|
||||
// open objects/arrays
|
||||
std::vector<std::vector<ValueLength>> _index; // Indices for starts
|
||||
// of subindex
|
||||
void reserveSpace(ValueLength len) {
|
||||
// Reserves len bytes at pos of the current state (top of stack)
|
||||
// or throws an exception
|
||||
if (_pos + len <= _size) {
|
||||
return; // All OK, we can just increase tos->pos by len
|
||||
}
|
||||
checkValueLength(_pos + len);
|
||||
|
||||
// Here are the mechanics of how this building process works:
|
||||
// The whole VPack being built starts at where _start points to
|
||||
// and uses at most _size bytes. The variable _pos keeps the
|
||||
// current write position. The method "set" simply writes a new
|
||||
// VPack subobject at the current write position and advances
|
||||
// it. Whenever one makes an array or object, a ValueLength for
|
||||
// the beginning of the value is pushed onto the _stack, which
|
||||
// remembers that we are in the process of building an array or
|
||||
// object. The _index vectors are used to collect information
|
||||
// for the index tables of arrays and objects, which are written
|
||||
// behind the subvalues. The add methods are used to keep track
|
||||
// of the new subvalue in _index followed by a set, and are
|
||||
// what the user from the outside calls. The close method seals
|
||||
// the innermost array or object that is currently being built
|
||||
// and pops a ValueLength off the _stack. The vectors in _index
|
||||
// stay until the next clearTemporary() is called to minimize
|
||||
// allocations. In the beginning, the _stack is empty, which
|
||||
// allows to build a sequence of unrelated VPack objects in the
|
||||
// buffer. Whenever the stack is empty, one can use the start,
|
||||
// size and slice methods to get out the ready built VPack
|
||||
// object(s).
|
||||
_buffer->prealloc(len);
|
||||
_start = _buffer->data();
|
||||
_size = _buffer->size();
|
||||
}
|
||||
|
||||
void reserveSpace (ValueLength len) {
|
||||
// Reserves len bytes at pos of the current state (top of stack)
|
||||
// or throws an exception
|
||||
if (_pos + len <= _size) {
|
||||
return; // All OK, we can just increase tos->pos by len
|
||||
}
|
||||
checkValueLength(_pos + len);
|
||||
// Sort the indices by attribute name:
|
||||
static void doActualSort(std::vector<SortEntry>& entries);
|
||||
|
||||
_buffer->prealloc(len);
|
||||
_start = _buffer->data();
|
||||
_size = _buffer->size();
|
||||
}
|
||||
// Find the actual bytes of the attribute name of the VPack value
|
||||
// at position base, also determine the length len of the attribute.
|
||||
// This takes into account the different possibilities for the format
|
||||
// of attribute names:
|
||||
static uint8_t const* findAttrName(uint8_t const* base, uint64_t& len);
|
||||
|
||||
// Sort the indices by attribute name:
|
||||
static void doActualSort (std::vector<SortEntry>& entries);
|
||||
static void sortObjectIndexShort(uint8_t* objBase,
|
||||
std::vector<ValueLength>& offsets);
|
||||
|
||||
// Find the actual bytes of the attribute name of the VPack value
|
||||
// at position base, also determine the length len of the attribute.
|
||||
// This takes into account the different possibilities for the format
|
||||
// of attribute names:
|
||||
static uint8_t const* findAttrName (uint8_t const* base, uint64_t& len);
|
||||
static void sortObjectIndexLong(uint8_t* objBase,
|
||||
std::vector<ValueLength>& offsets);
|
||||
|
||||
static void sortObjectIndexShort (uint8_t* objBase,
|
||||
std::vector<ValueLength>& offsets);
|
||||
static void sortObjectIndex(uint8_t* objBase,
|
||||
std::vector<ValueLength>& offsets);
|
||||
|
||||
static void sortObjectIndexLong (uint8_t* objBase,
|
||||
std::vector<ValueLength>& offsets);
|
||||
public:
|
||||
Options const* options;
|
||||
|
||||
static void sortObjectIndex (uint8_t* objBase,
|
||||
std::vector<ValueLength>& offsets);
|
||||
// Constructor and destructor:
|
||||
explicit Builder(std::shared_ptr<Buffer<uint8_t>>& buffer,
|
||||
Options const* options = &Options::Defaults)
|
||||
: _buffer(buffer), _pos(0), options(options) {
|
||||
if (_buffer.get() == nullptr) {
|
||||
throw Exception(Exception::InternalError, "Buffer cannot be a nullptr");
|
||||
}
|
||||
_start = _buffer->data();
|
||||
_size = _buffer->size();
|
||||
|
||||
public:
|
||||
|
||||
Options const* options;
|
||||
if (options == nullptr) {
|
||||
throw Exception(Exception::InternalError, "Options cannot be a nullptr");
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor and destructor:
|
||||
explicit 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();
|
||||
explicit 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");
|
||||
}
|
||||
}
|
||||
|
||||
if (options == nullptr) {
|
||||
throw Exception(Exception::InternalError, "Options cannot be a nullptr");
|
||||
}
|
||||
}
|
||||
// The rule of five:
|
||||
|
||||
explicit Builder (Options const* options = &Options::Defaults)
|
||||
: _buffer(new Buffer<uint8_t>()),
|
||||
_pos(0),
|
||||
options(options) {
|
||||
_start = _buffer->data();
|
||||
_size = _buffer->size();
|
||||
~Builder() {}
|
||||
|
||||
VELOCYPACK_ASSERT(options != nullptr);
|
||||
Builder(Builder const& that)
|
||||
: _buffer(that._buffer),
|
||||
_start(_buffer->data()),
|
||||
_size(_buffer->size()),
|
||||
_pos(that._pos),
|
||||
_stack(that._stack),
|
||||
_index(that._index),
|
||||
options(that.options) {
|
||||
if (that._buffer == nullptr) {
|
||||
throw Exception(Exception::InternalError,
|
||||
"Buffer of Builder is already gone");
|
||||
}
|
||||
}
|
||||
|
||||
if (options == nullptr) {
|
||||
throw Exception(Exception::InternalError, "Options cannot be a nullptr");
|
||||
}
|
||||
}
|
||||
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();
|
||||
_pos = that._pos;
|
||||
_stack = that._stack;
|
||||
_index = that._index;
|
||||
options = that.options;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// The rule of five:
|
||||
Builder(Builder&& that) {
|
||||
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();
|
||||
_pos = that._pos;
|
||||
_stack.clear();
|
||||
_stack.swap(that._stack);
|
||||
_index.clear();
|
||||
_index.swap(that._index);
|
||||
options = that.options;
|
||||
that._start = nullptr;
|
||||
that._size = 0;
|
||||
that._pos = 0;
|
||||
}
|
||||
|
||||
~Builder () {
|
||||
}
|
||||
Builder& operator=(Builder&& that) {
|
||||
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();
|
||||
_pos = that._pos;
|
||||
_stack.clear();
|
||||
_stack.swap(that._stack);
|
||||
_index.clear();
|
||||
_index.swap(that._index);
|
||||
options = that.options;
|
||||
that._start = nullptr;
|
||||
that._size = 0;
|
||||
that._pos = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Builder (Builder const& that)
|
||||
: _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");
|
||||
}
|
||||
}
|
||||
// get a const reference to the Builder's Buffer object
|
||||
std::shared_ptr<Buffer<uint8_t>> const& buffer() const { return _buffer; }
|
||||
|
||||
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();
|
||||
_pos = that._pos;
|
||||
_stack = that._stack;
|
||||
_index = that._index;
|
||||
options = that.options;
|
||||
VELOCYPACK_ASSERT(options != nullptr);
|
||||
return *this;
|
||||
}
|
||||
uint8_t const* data() const {
|
||||
if (_buffer == nullptr) {
|
||||
throw Exception(Exception::InternalError,
|
||||
"Buffer of Builder is already gone");
|
||||
}
|
||||
|
||||
Builder (Builder&& that) {
|
||||
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();
|
||||
_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 _buffer.get()->data();
|
||||
}
|
||||
|
||||
Builder& operator= (Builder&& that) {
|
||||
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();
|
||||
_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;
|
||||
}
|
||||
std::string toString() const;
|
||||
|
||||
// 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; }
|
||||
|
||||
uint8_t const* data () const {
|
||||
if (_buffer == nullptr) {
|
||||
throw Exception(Exception::InternalError, "Buffer of Builder is already gone");
|
||||
}
|
||||
static Builder clone(Slice const& slice,
|
||||
Options const* options = &Options::Defaults) {
|
||||
if (options == nullptr) {
|
||||
throw Exception(Exception::InternalError, "Options cannot be a nullptr");
|
||||
}
|
||||
|
||||
return _buffer.get()->data();
|
||||
}
|
||||
Builder b(options);
|
||||
b.add(slice);
|
||||
return std::move(b);
|
||||
}
|
||||
|
||||
std::string toString () const;
|
||||
|
||||
// get a non-const reference to the Builder's Buffer object
|
||||
std::shared_ptr<Buffer<uint8_t>>& buffer () {
|
||||
return _buffer;
|
||||
}
|
||||
// Clear and start from scratch:
|
||||
void clear() {
|
||||
_pos = 0;
|
||||
_stack.clear();
|
||||
}
|
||||
|
||||
static Builder clone (Slice const& slice, Options const* options = &Options::Defaults) {
|
||||
VELOCYPACK_ASSERT(options != nullptr);
|
||||
// Return a pointer to the start of the result:
|
||||
uint8_t* start() const {
|
||||
if (!isClosed()) {
|
||||
throw Exception(Exception::BuilderNotSealed);
|
||||
}
|
||||
return _start;
|
||||
}
|
||||
|
||||
Builder b(options);
|
||||
b.add(slice);
|
||||
return std::move(b);
|
||||
}
|
||||
// Return a Slice of the result:
|
||||
Slice slice() const { return Slice(start(), options); }
|
||||
|
||||
// Clear and start from scratch:
|
||||
void clear () {
|
||||
_pos = 0;
|
||||
_stack.clear();
|
||||
}
|
||||
// Compute the actual size here, but only when sealed
|
||||
ValueLength size() const {
|
||||
if (!isClosed()) {
|
||||
throw Exception(Exception::BuilderNotSealed);
|
||||
}
|
||||
return _pos;
|
||||
}
|
||||
|
||||
// Return a pointer to the start of the result:
|
||||
uint8_t* start () const {
|
||||
if (! isClosed()) {
|
||||
throw Exception(Exception::BuilderNotSealed);
|
||||
}
|
||||
return _start;
|
||||
}
|
||||
bool isClosed() const throw() { return _stack.empty(); }
|
||||
|
||||
// Return a Slice of the result:
|
||||
Slice slice () const {
|
||||
return Slice(start(), options);
|
||||
}
|
||||
// Add a subvalue into an object from a Value:
|
||||
uint8_t* add(std::string const& attrName, Value const& sub);
|
||||
|
||||
// Compute the actual size here, but only when sealed
|
||||
ValueLength size () const {
|
||||
if (! isClosed()) {
|
||||
throw Exception(Exception::BuilderNotSealed);
|
||||
}
|
||||
return _pos;
|
||||
}
|
||||
// Add a subvalue into an object from a Slice:
|
||||
uint8_t* add(std::string const& attrName, Slice const& sub);
|
||||
|
||||
bool isClosed () const throw() {
|
||||
return _stack.empty();
|
||||
}
|
||||
// Add a subvalue into an object from a ValuePair:
|
||||
uint8_t* add(std::string const& attrName, ValuePair const& sub);
|
||||
|
||||
// Add a subvalue into an object from a Value:
|
||||
uint8_t* add (std::string const& attrName, Value const& sub);
|
||||
|
||||
// Add a subvalue into an object from a Slice:
|
||||
uint8_t* add (std::string const& attrName, Slice const& sub);
|
||||
// Add a subvalue into an array from a Value:
|
||||
uint8_t* add(Value const& sub);
|
||||
|
||||
// Add a subvalue into an object from a ValuePair:
|
||||
uint8_t* add (std::string const& attrName, ValuePair const& sub);
|
||||
// Add a slice to an array
|
||||
uint8_t* add(Slice const& sub);
|
||||
|
||||
// Add a subvalue into an array from a Value:
|
||||
uint8_t* add (Value const& sub);
|
||||
|
||||
// Add a slice to an array
|
||||
uint8_t* add (Slice const& sub);
|
||||
// Add a subvalue into an array from a ValuePair:
|
||||
uint8_t* add(ValuePair const& sub);
|
||||
|
||||
// Add a subvalue into an array from a ValuePair:
|
||||
uint8_t* add (ValuePair const& sub);
|
||||
|
||||
// Seal the innermost array or object:
|
||||
void close ();
|
||||
// Seal the innermost array or object:
|
||||
void close();
|
||||
|
||||
// Remove last subvalue written to an (unclosed) object or array:
|
||||
// Throws if an error occurs.
|
||||
void removeLast ();
|
||||
// Remove last subvalue written to an (unclosed) object or array:
|
||||
// Throws if an error occurs.
|
||||
void removeLast();
|
||||
|
||||
// whether or not a specific key is present in an Object value
|
||||
bool hasKey (std::string const& key) const;
|
||||
// whether or not a specific key is present in an Object value
|
||||
bool hasKey(std::string const& key) const;
|
||||
|
||||
// return an attribute from an Object value
|
||||
Slice getKey (std::string const& key) const;
|
||||
// return an attribute from an Object value
|
||||
Slice getKey(std::string const& key) const;
|
||||
|
||||
// Syntactic sugar for add:
|
||||
Builder& operator() (std::string const& attrName, Value const& sub) {
|
||||
add(attrName, sub);
|
||||
return *this;
|
||||
}
|
||||
// Syntactic sugar for add:
|
||||
Builder& operator()(std::string const& attrName, Value const& sub) {
|
||||
add(attrName, sub);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Syntactic sugar for add:
|
||||
Builder& operator() (std::string const& attrName, ValuePair const& sub) {
|
||||
add(attrName, sub);
|
||||
return *this;
|
||||
}
|
||||
// Syntactic sugar for add:
|
||||
Builder& operator()(std::string const& attrName, ValuePair const& sub) {
|
||||
add(attrName, sub);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Syntactic sugar for add:
|
||||
Builder& operator() (std::string const& attrName, Slice const& sub) {
|
||||
add(attrName, sub);
|
||||
return *this;
|
||||
}
|
||||
// Syntactic sugar for add:
|
||||
Builder& operator()(std::string const& attrName, Slice const& sub) {
|
||||
add(attrName, sub);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Syntactic sugar for add:
|
||||
Builder& operator() (Value const& sub) {
|
||||
add(sub);
|
||||
return *this;
|
||||
}
|
||||
// Syntactic sugar for add:
|
||||
Builder& operator()(Value const& sub) {
|
||||
add(sub);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Syntactic sugar for add:
|
||||
Builder& operator() (ValuePair const& sub) {
|
||||
add(sub);
|
||||
return *this;
|
||||
}
|
||||
// Syntactic sugar for add:
|
||||
Builder& operator()(ValuePair const& sub) {
|
||||
add(sub);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Syntactic sugar for add:
|
||||
Builder& operator() (Slice const& sub) {
|
||||
add(sub);
|
||||
return *this;
|
||||
}
|
||||
// Syntactic sugar for add:
|
||||
Builder& operator()(Slice const& sub) {
|
||||
add(sub);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Syntactic sugar for close:
|
||||
Builder& operator() () {
|
||||
close();
|
||||
return *this;
|
||||
}
|
||||
// Syntactic sugar for close:
|
||||
Builder& operator()() {
|
||||
close();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void addNull () {
|
||||
reserveSpace(1);
|
||||
_start[_pos++] = 0x18;
|
||||
}
|
||||
void addNull() {
|
||||
reserveSpace(1);
|
||||
_start[_pos++] = 0x18;
|
||||
}
|
||||
|
||||
void addFalse () {
|
||||
reserveSpace(1);
|
||||
_start[_pos++] = 0x19;
|
||||
}
|
||||
void addFalse() {
|
||||
reserveSpace(1);
|
||||
_start[_pos++] = 0x19;
|
||||
}
|
||||
|
||||
void addTrue () {
|
||||
reserveSpace(1);
|
||||
_start[_pos++] = 0x1a;
|
||||
}
|
||||
void addTrue() {
|
||||
reserveSpace(1);
|
||||
_start[_pos++] = 0x1a;
|
||||
}
|
||||
|
||||
void addDouble (double v) {
|
||||
uint64_t dv;
|
||||
memcpy(&dv, &v, sizeof(double));
|
||||
ValueLength vSize = sizeof(double);
|
||||
reserveSpace(1 + vSize);
|
||||
_start[_pos++] = 0x1b;
|
||||
for (uint64_t x = dv; vSize > 0; vSize--) {
|
||||
_start[_pos++] = x & 0xff;
|
||||
x >>= 8;
|
||||
}
|
||||
}
|
||||
void addDouble(double v) {
|
||||
uint64_t dv;
|
||||
memcpy(&dv, &v, sizeof(double));
|
||||
ValueLength vSize = sizeof(double);
|
||||
reserveSpace(1 + vSize);
|
||||
_start[_pos++] = 0x1b;
|
||||
for (uint64_t x = dv; vSize > 0; vSize--) {
|
||||
_start[_pos++] = x & 0xff;
|
||||
x >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void addInt (int64_t v) {
|
||||
if (v >= 0 && v <= 9) {
|
||||
reserveSpace(1);
|
||||
_start[_pos++] = static_cast<uint8_t>(0x30 + v);
|
||||
}
|
||||
else if (v < 0 && v >= -6) {
|
||||
reserveSpace(1);
|
||||
_start[_pos++] = static_cast<uint8_t>(0x40 + v);
|
||||
}
|
||||
else {
|
||||
appendInt(v, 0x1f);
|
||||
}
|
||||
}
|
||||
void addInt(int64_t v) {
|
||||
if (v >= 0 && v <= 9) {
|
||||
reserveSpace(1);
|
||||
_start[_pos++] = static_cast<uint8_t>(0x30 + v);
|
||||
} else if (v < 0 && v >= -6) {
|
||||
reserveSpace(1);
|
||||
_start[_pos++] = static_cast<uint8_t>(0x40 + v);
|
||||
} else {
|
||||
appendInt(v, 0x1f);
|
||||
}
|
||||
}
|
||||
|
||||
void addUInt (uint64_t v) {
|
||||
if (v <= 9) {
|
||||
reserveSpace(1);
|
||||
_start[_pos++] = static_cast<uint8_t>(0x30 + v);
|
||||
}
|
||||
else {
|
||||
appendUInt(v, 0x27);
|
||||
}
|
||||
}
|
||||
void addUInt(uint64_t v) {
|
||||
if (v <= 9) {
|
||||
reserveSpace(1);
|
||||
_start[_pos++] = static_cast<uint8_t>(0x30 + v);
|
||||
} else {
|
||||
appendUInt(v, 0x27);
|
||||
}
|
||||
}
|
||||
|
||||
void addUTCDate (int64_t v) {
|
||||
uint8_t vSize = sizeof(int64_t); // is always 8
|
||||
uint64_t x = toUInt64(v);
|
||||
reserveSpace(1 + vSize);
|
||||
_start[_pos++] = 0x1c;
|
||||
appendLength(x, 8);
|
||||
}
|
||||
void addUTCDate(int64_t v) {
|
||||
uint8_t vSize = sizeof(int64_t); // is always 8
|
||||
uint64_t x = toUInt64(v);
|
||||
reserveSpace(1 + vSize);
|
||||
_start[_pos++] = 0x1c;
|
||||
appendLength(x, 8);
|
||||
}
|
||||
|
||||
uint8_t* addString (uint64_t strLen) {
|
||||
uint8_t* target;
|
||||
if (strLen > 126) {
|
||||
// long string
|
||||
_start[_pos++] = 0xbf;
|
||||
// write string length
|
||||
appendLength(strLen, 8);
|
||||
}
|
||||
else {
|
||||
// short string
|
||||
_start[_pos++] = static_cast<uint8_t>(0x40 + strLen);
|
||||
}
|
||||
target = _start + _pos;
|
||||
_pos += strLen;
|
||||
return target;
|
||||
}
|
||||
uint8_t* addString(uint64_t strLen) {
|
||||
uint8_t* target;
|
||||
if (strLen > 126) {
|
||||
// long string
|
||||
_start[_pos++] = 0xbf;
|
||||
// write string length
|
||||
appendLength(strLen, 8);
|
||||
} else {
|
||||
// short string
|
||||
_start[_pos++] = static_cast<uint8_t>(0x40 + strLen);
|
||||
}
|
||||
target = _start + _pos;
|
||||
_pos += strLen;
|
||||
return target;
|
||||
}
|
||||
|
||||
inline void addArray (bool unindexed = false) {
|
||||
addCompoundValue(unindexed ? 0x13 : 0x06);
|
||||
}
|
||||
inline void addArray(bool unindexed = false) {
|
||||
addCompoundValue(unindexed ? 0x13 : 0x06);
|
||||
}
|
||||
|
||||
inline void addObject (bool unindexed = false) {
|
||||
addCompoundValue(unindexed ? 0x14 : 0x0b);
|
||||
}
|
||||
// this is an alias for addArray()
|
||||
inline void openArray(bool unindexed = false) {
|
||||
addCompoundValue(unindexed ? 0x13 : 0x06);
|
||||
}
|
||||
|
||||
private:
|
||||
inline void addObject(bool unindexed = false) {
|
||||
addCompoundValue(unindexed ? 0x14 : 0x0b);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
uint8_t* addInternal (T const& sub) {
|
||||
if (! _stack.empty()) {
|
||||
ValueLength& tos = _stack.back();
|
||||
if (_start[tos] != 0x06 && _start[tos] != 0x13) {
|
||||
throw Exception(Exception::BuilderNeedOpenArray);
|
||||
}
|
||||
reportAdd(tos);
|
||||
}
|
||||
// this is an alias for addObject()
|
||||
inline void openObject(bool unindexed = false) {
|
||||
addCompoundValue(unindexed ? 0x14 : 0x0b);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
uint8_t* addInternal(T const& sub) {
|
||||
bool haveReported = false;
|
||||
if (!_stack.empty()) {
|
||||
ValueLength& tos = _stack.back();
|
||||
if (_start[tos] != 0x06 && _start[tos] != 0x13) {
|
||||
throw Exception(Exception::BuilderNeedOpenArray);
|
||||
}
|
||||
reportAdd(tos);
|
||||
haveReported = true;
|
||||
}
|
||||
try {
|
||||
return set(sub);
|
||||
} catch (...) {
|
||||
// clean up in case of an exception
|
||||
if (haveReported) {
|
||||
cleanupAdd();
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint8_t* addInternal(std::string const& attrName, T const& sub) {
|
||||
bool haveReported = false;
|
||||
if (!_stack.empty()) {
|
||||
ValueLength& tos = _stack.back();
|
||||
if (_start[tos] != 0x0b && _start[tos] != 0x14) {
|
||||
throw Exception(Exception::BuilderNeedOpenObject);
|
||||
}
|
||||
reportAdd(tos);
|
||||
haveReported = true;
|
||||
}
|
||||
|
||||
try {
|
||||
if (options->attributeTranslator != nullptr) {
|
||||
// check if a translation for the attribute name exists
|
||||
uint8_t const* translated =
|
||||
options->attributeTranslator->translate(attrName);
|
||||
|
||||
if (translated != nullptr) {
|
||||
set(Slice(options->attributeTranslator->translate(attrName),
|
||||
options));
|
||||
return set(sub);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
uint8_t* addInternal (std::string const& attrName, T const& sub) {
|
||||
if (! _stack.empty()) {
|
||||
ValueLength& tos = _stack.back();
|
||||
if (_start[tos] != 0x0b && _start[tos] != 0x14) {
|
||||
throw Exception(Exception::BuilderNeedOpenObject);
|
||||
}
|
||||
reportAdd(tos);
|
||||
}
|
||||
// otherwise fall through to regular behavior
|
||||
}
|
||||
|
||||
if (options->attributeTranslator != nullptr) {
|
||||
// check if a translation for the attribute name exists
|
||||
uint8_t const* translated = options->attributeTranslator->translate(attrName);
|
||||
set(Value(attrName, ValueType::String));
|
||||
return set(sub);
|
||||
} catch (...) {
|
||||
// clean up in case of an exception
|
||||
if (haveReported) {
|
||||
cleanupAdd();
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if (translated != nullptr) {
|
||||
set(Slice(options->attributeTranslator->translate(attrName), options));
|
||||
return set(sub);
|
||||
}
|
||||
// otherwise fall through to regular behavior
|
||||
}
|
||||
void addCompoundValue(uint8_t type) {
|
||||
reserveSpace(9);
|
||||
// an Array or Object is started:
|
||||
_stack.push_back(_pos);
|
||||
while (_stack.size() > _index.size()) {
|
||||
_index.emplace_back();
|
||||
}
|
||||
_index[_stack.size() - 1].clear();
|
||||
_start[_pos++] = type;
|
||||
memset(_start + _pos, 0, 8);
|
||||
_pos += 8; // Will be filled later with bytelength and nr subs
|
||||
}
|
||||
|
||||
set(Value(attrName, ValueType::String));
|
||||
return set(sub);
|
||||
}
|
||||
uint8_t* set(Value const& item);
|
||||
|
||||
void addCompoundValue (uint8_t type) {
|
||||
reserveSpace(9);
|
||||
// an Array or Object is started:
|
||||
_stack.push_back(_pos);
|
||||
while (_stack.size() > _index.size()) {
|
||||
_index.emplace_back();
|
||||
}
|
||||
_index[_stack.size() - 1].clear();
|
||||
_start[_pos++] = type;
|
||||
memset(_start + _pos, 0, 8);
|
||||
_pos += 8; // Will be filled later with bytelength and nr subs
|
||||
}
|
||||
uint8_t* set(ValuePair const& pair);
|
||||
|
||||
uint8_t* set (Value const& item);
|
||||
uint8_t* set(Slice const& item);
|
||||
|
||||
uint8_t* set (ValuePair const& pair);
|
||||
|
||||
uint8_t* set (Slice const& item);
|
||||
|
||||
void reportAdd (ValueLength base) {
|
||||
size_t depth = _stack.size() - 1;
|
||||
_index[depth].push_back(_pos - base);
|
||||
}
|
||||
void cleanupAdd() {
|
||||
size_t depth = _stack.size() - 1;
|
||||
_index[depth].pop_back();
|
||||
}
|
||||
|
||||
void appendLength (ValueLength v, uint64_t n) {
|
||||
reserveSpace(n);
|
||||
for (uint64_t i = 0; i < n; ++i) {
|
||||
_start[_pos++] = v & 0xff;
|
||||
v >>= 8;
|
||||
}
|
||||
}
|
||||
void reportAdd(ValueLength base) {
|
||||
size_t depth = _stack.size() - 1;
|
||||
_index[depth].push_back(_pos - base);
|
||||
}
|
||||
|
||||
void appendUInt (uint64_t v, uint8_t base) {
|
||||
reserveSpace(9);
|
||||
ValueLength save = _pos++;
|
||||
uint8_t vSize = 0;
|
||||
do {
|
||||
vSize++;
|
||||
_start[_pos++] = static_cast<uint8_t>(v & 0xff);
|
||||
v >>= 8;
|
||||
}
|
||||
while (v != 0);
|
||||
_start[save] = base + vSize;
|
||||
}
|
||||
void appendLength(ValueLength v, uint64_t n) {
|
||||
reserveSpace(n);
|
||||
for (uint64_t i = 0; i < n; ++i) {
|
||||
_start[_pos++] = v & 0xff;
|
||||
v >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
// returns number of bytes required to store the value in 2s-complement
|
||||
static inline uint8_t intLength (int64_t value) {
|
||||
if (value >= -0x80 && value <= 0x7f) {
|
||||
// shortcut for the common case
|
||||
return 1;
|
||||
}
|
||||
uint64_t x = value >= 0 ? static_cast<uint64_t>(value)
|
||||
: static_cast<uint64_t>(-(value + 1));
|
||||
uint8_t xSize = 0;
|
||||
do {
|
||||
xSize++;
|
||||
x >>= 8;
|
||||
}
|
||||
while (x >= 0x80);
|
||||
return xSize + 1;
|
||||
}
|
||||
void appendUInt(uint64_t v, uint8_t base) {
|
||||
reserveSpace(9);
|
||||
ValueLength save = _pos++;
|
||||
uint8_t vSize = 0;
|
||||
do {
|
||||
vSize++;
|
||||
_start[_pos++] = static_cast<uint8_t>(v & 0xff);
|
||||
v >>= 8;
|
||||
} while (v != 0);
|
||||
_start[save] = base + vSize;
|
||||
}
|
||||
|
||||
void appendInt (int64_t v, uint8_t base) {
|
||||
uint8_t vSize = intLength(v);
|
||||
uint64_t x;
|
||||
if (vSize == 8) {
|
||||
x = toUInt64(v);
|
||||
}
|
||||
else {
|
||||
int64_t shift = 1LL << (vSize * 8 - 1); // will never overflow!
|
||||
x = v >= 0 ? static_cast<uint64_t>(v)
|
||||
: static_cast<uint64_t>(v + shift) + shift;
|
||||
}
|
||||
reserveSpace(1 + vSize);
|
||||
_start[_pos++] = base + vSize;
|
||||
while (vSize-- > 0) {
|
||||
_start[_pos++] = x & 0xff;
|
||||
x >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void checkAttributeUniqueness (Slice const& obj) const;
|
||||
};
|
||||
// returns number of bytes required to store the value in 2s-complement
|
||||
static inline uint8_t intLength(int64_t value) {
|
||||
if (value >= -0x80 && value <= 0x7f) {
|
||||
// shortcut for the common case
|
||||
return 1;
|
||||
}
|
||||
uint64_t x = value >= 0 ? static_cast<uint64_t>(value)
|
||||
: static_cast<uint64_t>(-(value + 1));
|
||||
uint8_t xSize = 0;
|
||||
do {
|
||||
xSize++;
|
||||
x >>= 8;
|
||||
} while (x >= 0x80);
|
||||
return xSize + 1;
|
||||
}
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
void appendInt(int64_t v, uint8_t base) {
|
||||
uint8_t vSize = intLength(v);
|
||||
uint64_t x;
|
||||
if (vSize == 8) {
|
||||
x = toUInt64(v);
|
||||
} else {
|
||||
int64_t shift = 1LL << (vSize * 8 - 1); // will never overflow!
|
||||
x = v >= 0 ? static_cast<uint64_t>(v)
|
||||
: static_cast<uint64_t>(v + shift) + shift;
|
||||
}
|
||||
reserveSpace(1 + vSize);
|
||||
_start[_pos++] = base + vSize;
|
||||
while (vSize-- > 0) {
|
||||
_start[_pos++] = x & 0xff;
|
||||
x >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void checkAttributeUniqueness(Slice const& obj) const;
|
||||
};
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
|
|
|
@ -37,119 +37,142 @@
|
|||
#include "velocypack/Slice.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
|
||||
class Collection {
|
||||
namespace velocypack {
|
||||
|
||||
public:
|
||||
class Collection {
|
||||
public:
|
||||
enum VisitationOrder { PreOrder = 1, PostOrder = 2 };
|
||||
|
||||
enum VisitationOrder {
|
||||
PreOrder = 1,
|
||||
PostOrder = 2
|
||||
};
|
||||
Collection() = delete;
|
||||
Collection(Collection const&) = delete;
|
||||
Collection& operator=(Collection const&) = delete;
|
||||
|
||||
Collection () = delete;
|
||||
Collection (Collection const&) = delete;
|
||||
Collection& operator= (Collection const&) = delete;
|
||||
static void forEach(Slice const& slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb);
|
||||
|
||||
static void forEach (Slice const& slice, std::function<bool(Slice const&, ValueLength)> const& cb);
|
||||
|
||||
static void forEach (Slice const* slice, std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
return forEach(*slice, cb);
|
||||
}
|
||||
|
||||
static Builder filter (Slice const& slice, std::function<bool(Slice const&, ValueLength)> const& cb);
|
||||
|
||||
static Builder filter (Slice const* slice, std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
return filter(*slice, cb);
|
||||
}
|
||||
|
||||
static Slice find (Slice const& slice, std::function<bool(Slice const&, ValueLength)> const& cb);
|
||||
|
||||
static Slice find (Slice const* slice, std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
return find(*slice, cb);
|
||||
}
|
||||
|
||||
static bool contains (Slice const& slice, std::function<bool(Slice const&, ValueLength)> const& cb);
|
||||
|
||||
static bool contains (Slice const* slice, std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
return contains(*slice, cb);
|
||||
}
|
||||
|
||||
static bool all (Slice const& slice, std::function<bool(Slice const&, ValueLength)> const& cb);
|
||||
|
||||
static bool all (Slice const* slice, std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
return all(*slice, cb);
|
||||
}
|
||||
|
||||
static bool any (Slice const& slice, std::function<bool(Slice const&, ValueLength)> const& cb);
|
||||
|
||||
static bool any (Slice const* slice, std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
return any(*slice, cb);
|
||||
}
|
||||
static void forEach(
|
||||
Slice const* slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
return forEach(*slice, cb);
|
||||
}
|
||||
|
||||
static std::vector<std::string> keys (Slice const& slice);
|
||||
|
||||
static std::vector<std::string> keys (Slice const* slice) {
|
||||
return keys(*slice);
|
||||
}
|
||||
|
||||
static void keys (Slice const& slice, std::vector<std::string>& result);
|
||||
|
||||
static void keys (Slice const* slice, std::vector<std::string>& result) {
|
||||
return keys(*slice, result);
|
||||
}
|
||||
|
||||
static void keys (Slice const& slice, std::unordered_set<std::string>& result);
|
||||
|
||||
static void keys (Slice const* slice, std::unordered_set<std::string>& result) {
|
||||
return keys(*slice, result);
|
||||
}
|
||||
|
||||
static Builder values (Slice const& slice);
|
||||
|
||||
static Builder values (Slice const* slice) {
|
||||
return values(*slice);
|
||||
}
|
||||
static Builder filter(
|
||||
Slice const& slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb);
|
||||
|
||||
static Builder keep (Slice const& slice, std::vector<std::string> const& keys);
|
||||
static Builder filter(
|
||||
Slice const* slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
return filter(*slice, cb);
|
||||
}
|
||||
|
||||
static Builder keep (Slice const& slice, std::unordered_set<std::string> const& keys);
|
||||
|
||||
static Builder keep (Slice const* slice, std::vector<std::string> const& keys) {
|
||||
return keep(*slice, keys);
|
||||
}
|
||||
static Slice find(Slice const& slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb);
|
||||
|
||||
static Builder keep (Slice const* slice, std::unordered_set<std::string> const& keys) {
|
||||
return keep(*slice, keys);
|
||||
}
|
||||
static Slice find(Slice const* slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
return find(*slice, cb);
|
||||
}
|
||||
|
||||
static Builder remove (Slice const& slice, std::vector<std::string> const& keys);
|
||||
static bool contains(
|
||||
Slice const& slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb);
|
||||
|
||||
static Builder remove (Slice const& slice, std::unordered_set<std::string> const& keys);
|
||||
|
||||
static Builder remove (Slice const* slice, std::vector<std::string> const& keys) {
|
||||
return remove(*slice, keys);
|
||||
}
|
||||
static bool contains(
|
||||
Slice const* slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
return contains(*slice, cb);
|
||||
}
|
||||
|
||||
static Builder remove (Slice const* slice, std::unordered_set<std::string> const& keys) {
|
||||
return remove(*slice, keys);
|
||||
}
|
||||
static bool all(Slice const& slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb);
|
||||
|
||||
static Builder merge (Slice const& left, Slice const& right, bool mergeValues);
|
||||
static bool all(Slice const* slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
return all(*slice, cb);
|
||||
}
|
||||
|
||||
static Builder merge (Slice const* left, Slice const* right, bool mergeValues) {
|
||||
return merge(*left, *right, mergeValues);
|
||||
}
|
||||
static bool any(Slice const& slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb);
|
||||
|
||||
static void visitRecursive (Slice const& slice, VisitationOrder order, std::function<bool(Slice const&, Slice const&)> const& func);
|
||||
static bool any(Slice const* slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
return any(*slice, cb);
|
||||
}
|
||||
|
||||
static void visitRecursive (Slice const* slice, VisitationOrder order, std::function<bool(Slice const&, Slice const&)> const& func) {
|
||||
visitRecursive(*slice, order, func);
|
||||
}
|
||||
};
|
||||
static std::vector<std::string> keys(Slice const& slice);
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
static std::vector<std::string> keys(Slice const* slice) {
|
||||
return keys(*slice);
|
||||
}
|
||||
|
||||
static void keys(Slice const& slice, std::vector<std::string>& result);
|
||||
|
||||
static void keys(Slice const* slice, std::vector<std::string>& result) {
|
||||
return keys(*slice, result);
|
||||
}
|
||||
|
||||
static void keys(Slice const& slice, std::unordered_set<std::string>& result);
|
||||
|
||||
static void keys(Slice const* slice,
|
||||
std::unordered_set<std::string>& result) {
|
||||
return keys(*slice, result);
|
||||
}
|
||||
|
||||
static Builder values(Slice const& slice);
|
||||
|
||||
static Builder values(Slice const* slice) { return values(*slice); }
|
||||
|
||||
static Builder keep(Slice const& slice, std::vector<std::string> const& keys);
|
||||
|
||||
static Builder keep(Slice const& slice,
|
||||
std::unordered_set<std::string> const& keys);
|
||||
|
||||
static Builder keep(Slice const* slice,
|
||||
std::vector<std::string> const& keys) {
|
||||
return keep(*slice, keys);
|
||||
}
|
||||
|
||||
static Builder keep(Slice const* slice,
|
||||
std::unordered_set<std::string> const& keys) {
|
||||
return keep(*slice, keys);
|
||||
}
|
||||
|
||||
static Builder remove(Slice const& slice,
|
||||
std::vector<std::string> const& keys);
|
||||
|
||||
static Builder remove(Slice const& slice,
|
||||
std::unordered_set<std::string> const& keys);
|
||||
|
||||
static Builder remove(Slice const* slice,
|
||||
std::vector<std::string> const& keys) {
|
||||
return remove(*slice, keys);
|
||||
}
|
||||
|
||||
static Builder remove(Slice const* slice,
|
||||
std::unordered_set<std::string> const& keys) {
|
||||
return remove(*slice, keys);
|
||||
}
|
||||
|
||||
static Builder merge(Slice const& left, Slice const& right, bool mergeValues);
|
||||
|
||||
static Builder merge(Slice const* left, Slice const* right,
|
||||
bool mergeValues) {
|
||||
return merge(*left, *right, mergeValues);
|
||||
}
|
||||
|
||||
static void visitRecursive(
|
||||
Slice const& slice, VisitationOrder order,
|
||||
std::function<bool(Slice const&, Slice const&)> const& func);
|
||||
|
||||
static void visitRecursive(
|
||||
Slice const* slice, VisitationOrder order,
|
||||
std::function<bool(Slice const&, Slice const&)> const& func) {
|
||||
visitRecursive(*slice, order, func);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,125 +36,117 @@
|
|||
#include "velocypack/Slice.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
namespace velocypack {
|
||||
|
||||
// Dumps VPack into a JSON output string
|
||||
class Dumper {
|
||||
// Dumps VPack into a JSON output string
|
||||
class Dumper {
|
||||
public:
|
||||
Options const* options;
|
||||
|
||||
public:
|
||||
Dumper(Dumper const&) = delete;
|
||||
Dumper& operator=(Dumper const&) = delete;
|
||||
|
||||
Options const* options;
|
||||
|
||||
Dumper (Dumper const&) = delete;
|
||||
Dumper& operator= (Dumper const&) = delete;
|
||||
Dumper(Sink* sink, Options const* options = &Options::Defaults)
|
||||
: options(options), _sink(sink), _indentation(0) {
|
||||
if (sink == nullptr) {
|
||||
throw Exception(Exception::InternalError, "Sink cannot be a nullptr");
|
||||
}
|
||||
if (options == nullptr) {
|
||||
throw Exception(Exception::InternalError, "Options cannot be a nullptr");
|
||||
}
|
||||
}
|
||||
|
||||
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() {}
|
||||
|
||||
~Dumper () {
|
||||
}
|
||||
Sink* sink() const { return _sink; }
|
||||
|
||||
Sink* sink () const {
|
||||
return _sink;
|
||||
}
|
||||
void dump(Slice const& slice) {
|
||||
_indentation = 0;
|
||||
_sink->reserve(slice.byteSize());
|
||||
dumpValue(&slice);
|
||||
}
|
||||
|
||||
void dump (Slice const& slice) {
|
||||
_indentation = 0;
|
||||
_sink->reserve(slice.byteSize());
|
||||
dumpValue(&slice);
|
||||
}
|
||||
void dump(Slice const* slice) { dump(*slice); }
|
||||
|
||||
void dump (Slice const* slice) {
|
||||
dump(*slice);
|
||||
}
|
||||
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) {
|
||||
Dumper dumper(sink, options);
|
||||
dumper.dump(slice);
|
||||
}
|
||||
static void dump(Slice const* slice, Sink* sink,
|
||||
Options const* options = &Options::Defaults) {
|
||||
dump(*slice, sink, options);
|
||||
}
|
||||
|
||||
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) {
|
||||
std::string buffer;
|
||||
StringSink sink(&buffer);
|
||||
dump(slice, &sink, options);
|
||||
return std::move(buffer);
|
||||
}
|
||||
|
||||
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(buffer);
|
||||
}
|
||||
static std::string toString(Slice const* slice,
|
||||
Options const* options = &Options::Defaults) {
|
||||
return std::move(toString(*slice, options));
|
||||
}
|
||||
|
||||
static std::string toString (Slice const* slice, Options const* options = &Options::Defaults) {
|
||||
return std::move(toString(*slice, options));
|
||||
}
|
||||
void append(Slice const& slice) { dumpValue(&slice); }
|
||||
|
||||
void append (Slice const& slice) {
|
||||
dumpValue(&slice);
|
||||
}
|
||||
void append(Slice const* slice) { dumpValue(slice); }
|
||||
|
||||
void append (Slice const* slice) {
|
||||
dumpValue(slice);
|
||||
}
|
||||
void appendString(char const* src, ValueLength len) {
|
||||
_sink->reserve(2 + len);
|
||||
_sink->push_back('"');
|
||||
dumpString(src, len);
|
||||
_sink->push_back('"');
|
||||
}
|
||||
|
||||
void appendString (char const* src, ValueLength len) {
|
||||
_sink->reserve(2 + len);
|
||||
_sink->push_back('"');
|
||||
dumpString(src, len);
|
||||
_sink->push_back('"');
|
||||
}
|
||||
void appendString(std::string const& str) {
|
||||
_sink->reserve(2 + str.size());
|
||||
_sink->push_back('"');
|
||||
dumpString(str.c_str(), str.size());
|
||||
_sink->push_back('"');
|
||||
}
|
||||
|
||||
void appendString (std::string const& str) {
|
||||
_sink->reserve(2 + str.size());
|
||||
_sink->push_back('"');
|
||||
dumpString(str.c_str(), str.size());
|
||||
_sink->push_back('"');
|
||||
}
|
||||
|
||||
void appendUInt (uint64_t);
|
||||
void appendUInt(uint64_t);
|
||||
|
||||
private:
|
||||
private:
|
||||
void dumpInteger(Slice const*);
|
||||
|
||||
void dumpInteger (Slice const*);
|
||||
void dumpString(char const*, ValueLength);
|
||||
|
||||
void dumpString (char const*, ValueLength);
|
||||
|
||||
void dumpValue (Slice const& slice, Slice const* base = nullptr) {
|
||||
dumpValue(&slice, base);
|
||||
}
|
||||
void dumpValue(Slice const& slice, Slice const* base = nullptr) {
|
||||
dumpValue(&slice, base);
|
||||
}
|
||||
|
||||
void dumpValue (Slice const*, Slice const* = nullptr);
|
||||
void dumpValue(Slice const*, Slice const* = nullptr);
|
||||
|
||||
void indent () {
|
||||
size_t n = _indentation;
|
||||
_sink->reserve(n);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
_sink->append(" ", 2);
|
||||
}
|
||||
}
|
||||
void indent() {
|
||||
size_t n = _indentation;
|
||||
_sink->reserve(n);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
_sink->append(" ", 2);
|
||||
}
|
||||
}
|
||||
|
||||
void handleUnsupportedType (Slice const*) {
|
||||
if (options->unsupportedTypeBehavior == Options::NullifyUnsupportedType) {
|
||||
_sink->append("null", 4);
|
||||
return;
|
||||
}
|
||||
void handleUnsupportedType(Slice const*) {
|
||||
if (options->unsupportedTypeBehavior == Options::NullifyUnsupportedType) {
|
||||
_sink->append("null", 4);
|
||||
return;
|
||||
}
|
||||
|
||||
throw Exception(Exception::NoJsonEquivalent);
|
||||
}
|
||||
|
||||
private:
|
||||
throw Exception(Exception::NoJsonEquivalent);
|
||||
}
|
||||
|
||||
Sink* _sink;
|
||||
|
||||
int _indentation;
|
||||
private:
|
||||
Sink* _sink;
|
||||
|
||||
};
|
||||
int _indentation;
|
||||
};
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,123 +34,118 @@
|
|||
#include "velocypack/velocypack-common.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
namespace velocypack {
|
||||
|
||||
// base exception class
|
||||
struct Exception : std::exception {
|
||||
public:
|
||||
enum ExceptionType {
|
||||
InternalError = 1,
|
||||
NotImplemented = 2,
|
||||
// base exception class
|
||||
struct Exception : std::exception {
|
||||
public:
|
||||
enum ExceptionType {
|
||||
InternalError = 1,
|
||||
NotImplemented = 2,
|
||||
|
||||
NoJsonEquivalent = 10,
|
||||
ParseError = 11,
|
||||
UnexpectedControlCharacter = 12,
|
||||
IndexOutOfBounds = 13,
|
||||
NumberOutOfRange = 14,
|
||||
InvalidUtf8Sequence = 15,
|
||||
InvalidAttributePath = 16,
|
||||
InvalidValueType = 17,
|
||||
DuplicateAttributeName = 18,
|
||||
NeedCustomTypeHandler = 19,
|
||||
NeedAttributeTranslator = 20,
|
||||
CannotTranslateKey = 21,
|
||||
KeyNotFound = 22,
|
||||
NoJsonEquivalent = 10,
|
||||
ParseError = 11,
|
||||
UnexpectedControlCharacter = 12,
|
||||
IndexOutOfBounds = 13,
|
||||
NumberOutOfRange = 14,
|
||||
InvalidUtf8Sequence = 15,
|
||||
InvalidAttributePath = 16,
|
||||
InvalidValueType = 17,
|
||||
DuplicateAttributeName = 18,
|
||||
NeedCustomTypeHandler = 19,
|
||||
NeedAttributeTranslator = 20,
|
||||
CannotTranslateKey = 21,
|
||||
KeyNotFound = 22,
|
||||
|
||||
BuilderNotSealed = 30,
|
||||
BuilderNeedOpenObject = 31,
|
||||
BuilderNeedOpenArray = 32,
|
||||
BuilderNeedOpenCompound = 33,
|
||||
BuilderUnexpectedType = 34,
|
||||
BuilderUnexpectedValue = 35,
|
||||
BuilderNeedSubvalue = 36,
|
||||
BuilderNotSealed = 30,
|
||||
BuilderNeedOpenObject = 31,
|
||||
BuilderNeedOpenArray = 32,
|
||||
BuilderNeedOpenCompound = 33,
|
||||
BuilderUnexpectedType = 34,
|
||||
BuilderUnexpectedValue = 35,
|
||||
BuilderNeedSubvalue = 36,
|
||||
BuilderExternalsDisallowed = 37,
|
||||
|
||||
UnknownError = 999
|
||||
};
|
||||
UnknownError = 999
|
||||
};
|
||||
|
||||
private:
|
||||
ExceptionType _type;
|
||||
std::string _msg;
|
||||
private:
|
||||
ExceptionType _type;
|
||||
std::string _msg;
|
||||
|
||||
public:
|
||||
public:
|
||||
Exception(ExceptionType type, std::string const& msg)
|
||||
: _type(type), _msg(msg) {}
|
||||
|
||||
Exception (ExceptionType type, std::string const& msg) : _type(type), _msg(msg) {
|
||||
}
|
||||
|
||||
Exception (ExceptionType type, char const* msg) : _type(type), _msg(msg) {
|
||||
}
|
||||
|
||||
explicit Exception (ExceptionType type) : Exception(type, message(type)) {
|
||||
}
|
||||
|
||||
char const* what() const throw() {
|
||||
return _msg.c_str();
|
||||
}
|
||||
Exception(ExceptionType type, char const* msg) : _type(type), _msg(msg) {}
|
||||
|
||||
ExceptionType errorCode () const throw() {
|
||||
return _type;
|
||||
}
|
||||
explicit Exception(ExceptionType type) : Exception(type, message(type)) {}
|
||||
|
||||
static char const* message (ExceptionType type) throw() {
|
||||
switch (type) {
|
||||
case InternalError:
|
||||
return "Internal error";
|
||||
case NotImplemented:
|
||||
return "Not implemented";
|
||||
case NoJsonEquivalent:
|
||||
return "Type has no equivalent in JSON";
|
||||
case ParseError:
|
||||
return "Parse error";
|
||||
case UnexpectedControlCharacter:
|
||||
return "Unexpected control character";
|
||||
case DuplicateAttributeName:
|
||||
return "Duplicate attribute name";
|
||||
case IndexOutOfBounds:
|
||||
return "Index out of bounds";
|
||||
case NumberOutOfRange:
|
||||
return "Number out of range";
|
||||
case InvalidUtf8Sequence:
|
||||
return "Invalid UTF-8 sequence";
|
||||
case InvalidAttributePath:
|
||||
return "Invalid attribute path";
|
||||
case InvalidValueType:
|
||||
return "Invalid value type for operation";
|
||||
case NeedCustomTypeHandler:
|
||||
return "Cannot execute operation without custom type handler";
|
||||
case NeedAttributeTranslator:
|
||||
return "Cannot execute operation without attribute translator";
|
||||
case CannotTranslateKey:
|
||||
return "Cannot translate key";
|
||||
case KeyNotFound:
|
||||
return "Key not found";
|
||||
case BuilderNotSealed:
|
||||
return "Builder value not yet sealed";
|
||||
case BuilderNeedOpenObject:
|
||||
return "Need open Object";
|
||||
case BuilderNeedOpenArray:
|
||||
return "Need open Array";
|
||||
case BuilderNeedSubvalue:
|
||||
return "Need subvalue in current Object or Array";
|
||||
case BuilderNeedOpenCompound:
|
||||
return "Need open compound value (Array or Object)";
|
||||
case BuilderUnexpectedType:
|
||||
return "Unexpected type";
|
||||
case BuilderUnexpectedValue:
|
||||
return "Unexpected value";
|
||||
char const* what() const throw() { return _msg.c_str(); }
|
||||
|
||||
case UnknownError:
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
ExceptionType errorCode() const throw() { return _type; }
|
||||
|
||||
};
|
||||
static char const* message(ExceptionType type) throw() {
|
||||
switch (type) {
|
||||
case InternalError:
|
||||
return "Internal error";
|
||||
case NotImplemented:
|
||||
return "Not implemented";
|
||||
case NoJsonEquivalent:
|
||||
return "Type has no equivalent in JSON";
|
||||
case ParseError:
|
||||
return "Parse error";
|
||||
case UnexpectedControlCharacter:
|
||||
return "Unexpected control character";
|
||||
case DuplicateAttributeName:
|
||||
return "Duplicate attribute name";
|
||||
case IndexOutOfBounds:
|
||||
return "Index out of bounds";
|
||||
case NumberOutOfRange:
|
||||
return "Number out of range";
|
||||
case InvalidUtf8Sequence:
|
||||
return "Invalid UTF-8 sequence";
|
||||
case InvalidAttributePath:
|
||||
return "Invalid attribute path";
|
||||
case InvalidValueType:
|
||||
return "Invalid value type for operation";
|
||||
case NeedCustomTypeHandler:
|
||||
return "Cannot execute operation without custom type handler";
|
||||
case NeedAttributeTranslator:
|
||||
return "Cannot execute operation without attribute translator";
|
||||
case CannotTranslateKey:
|
||||
return "Cannot translate key";
|
||||
case KeyNotFound:
|
||||
return "Key not found";
|
||||
case BuilderNotSealed:
|
||||
return "Builder value not yet sealed";
|
||||
case BuilderNeedOpenObject:
|
||||
return "Need open Object";
|
||||
case BuilderNeedOpenArray:
|
||||
return "Need open Array";
|
||||
case BuilderNeedSubvalue:
|
||||
return "Need subvalue in current Object or Array";
|
||||
case BuilderNeedOpenCompound:
|
||||
return "Need open compound value (Array or Object)";
|
||||
case BuilderUnexpectedType:
|
||||
return "Unexpected type";
|
||||
case BuilderUnexpectedValue:
|
||||
return "Unexpected value";
|
||||
case BuilderExternalsDisallowed:
|
||||
return "Externals are not allowed in this configuration";
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
case UnknownError:
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
std::ostream& operator<< (std::ostream&, arangodb::velocypack::Exception const*);
|
||||
|
||||
std::ostream& operator<< (std::ostream&, arangodb::velocypack::Exception const&);
|
||||
std::ostream& operator<<(std::ostream&, arangodb::velocypack::Exception const*);
|
||||
|
||||
std::ostream& operator<<(std::ostream&, arangodb::velocypack::Exception const&);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,31 +35,31 @@
|
|||
#include "velocypack/ValueType.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
namespace velocypack {
|
||||
|
||||
struct HexDump {
|
||||
HexDump () = delete;
|
||||
struct HexDump {
|
||||
HexDump() = delete;
|
||||
|
||||
HexDump (Slice const& slice, int valuesPerLine = 16, std::string const& separator = " ")
|
||||
: slice(slice), valuesPerLine(valuesPerLine), separator(separator) {
|
||||
}
|
||||
HexDump(Slice const& slice, int valuesPerLine = 16,
|
||||
std::string const& separator = " ")
|
||||
: slice(slice), valuesPerLine(valuesPerLine), separator(separator) {}
|
||||
|
||||
HexDump (Slice const* slice, int valuesPerLine = 16, std::string const& separator = " ")
|
||||
: HexDump(*slice, valuesPerLine, separator) {
|
||||
}
|
||||
HexDump(Slice const* slice, int valuesPerLine = 16,
|
||||
std::string const& separator = " ")
|
||||
: HexDump(*slice, valuesPerLine, separator) {}
|
||||
|
||||
static std::string toHex (uint8_t value);
|
||||
static std::string toHex(uint8_t value);
|
||||
|
||||
Slice const slice;
|
||||
int valuesPerLine;
|
||||
std::string separator;
|
||||
};
|
||||
Slice const slice;
|
||||
int valuesPerLine;
|
||||
std::string separator;
|
||||
};
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
std::ostream& operator<< (std::ostream&, arangodb::velocypack::HexDump const*);
|
||||
std::ostream& operator<<(std::ostream&, arangodb::velocypack::HexDump const*);
|
||||
|
||||
std::ostream& operator<< (std::ostream&, arangodb::velocypack::HexDump const&);
|
||||
std::ostream& operator<<(std::ostream&, arangodb::velocypack::HexDump const&);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,283 +36,251 @@
|
|||
#include "velocypack/ValueType.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
namespace velocypack {
|
||||
|
||||
class ArrayIterator {
|
||||
class ArrayIterator {
|
||||
public:
|
||||
ArrayIterator() = delete;
|
||||
|
||||
public:
|
||||
ArrayIterator(Slice const& slice)
|
||||
: _slice(slice), _size(_slice.length()), _position(0), _current(nullptr) {
|
||||
if (slice.type() != ValueType::Array) {
|
||||
throw Exception(Exception::InvalidValueType, "Expecting Array slice");
|
||||
}
|
||||
|
||||
ArrayIterator () = delete;
|
||||
if (slice.head() == 0x13 && slice.length() > 0) {
|
||||
_current = slice.at(0).start();
|
||||
}
|
||||
}
|
||||
|
||||
ArrayIterator (Slice const& slice)
|
||||
: _slice(slice), _size(_slice.length()), _position(0), _current(nullptr) {
|
||||
ArrayIterator(ArrayIterator const& other)
|
||||
: _slice(other._slice),
|
||||
_size(other._size),
|
||||
_position(other._position),
|
||||
_current(other._current) {}
|
||||
|
||||
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), _current(other._current) {
|
||||
}
|
||||
|
||||
ArrayIterator& operator= (ArrayIterator const& other) {
|
||||
_slice = other._slice;
|
||||
_size = other._size;
|
||||
_position = other._position;
|
||||
_current = other._current;
|
||||
return *this;
|
||||
}
|
||||
ArrayIterator& operator=(ArrayIterator const& other) {
|
||||
_slice = other._slice;
|
||||
_size = other._size;
|
||||
_position = other._position;
|
||||
_current = other._current;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// prefix ++
|
||||
ArrayIterator& operator++ () {
|
||||
++_position;
|
||||
if (_position <= _size && _current != nullptr) {
|
||||
_current += Slice(_current, _slice.options).byteSize();
|
||||
}
|
||||
else {
|
||||
_current = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
// postfix ++
|
||||
ArrayIterator operator++(int) {
|
||||
ArrayIterator result(*this);
|
||||
++(*this);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator!= (ArrayIterator const& other) const {
|
||||
return _position != other._position;
|
||||
}
|
||||
bool operator!=(ArrayIterator const& other) const {
|
||||
return _position != other._position;
|
||||
}
|
||||
|
||||
Slice operator* () const {
|
||||
if (_current != nullptr) {
|
||||
return Slice(_current, _slice.options);
|
||||
}
|
||||
return _slice.at(_position);
|
||||
}
|
||||
Slice operator*() const {
|
||||
if (_current != nullptr) {
|
||||
return Slice(_current, _slice.options);
|
||||
}
|
||||
return _slice.at(_position);
|
||||
}
|
||||
|
||||
ArrayIterator begin () {
|
||||
return ArrayIterator(_slice);
|
||||
}
|
||||
ArrayIterator begin() { return ArrayIterator(_slice); }
|
||||
|
||||
ArrayIterator begin () const {
|
||||
return ArrayIterator(_slice);
|
||||
}
|
||||
ArrayIterator begin() const { return ArrayIterator(_slice); }
|
||||
|
||||
ArrayIterator end () {
|
||||
auto it = ArrayIterator(_slice);
|
||||
it._position = it._size;
|
||||
return it;
|
||||
}
|
||||
ArrayIterator end() {
|
||||
auto it = ArrayIterator(_slice);
|
||||
it._position = it._size;
|
||||
return it;
|
||||
}
|
||||
|
||||
ArrayIterator end () const {
|
||||
auto it = ArrayIterator(_slice);
|
||||
it._position = it._size;
|
||||
return it;
|
||||
}
|
||||
|
||||
inline bool valid () const throw() {
|
||||
return (_position < _size);
|
||||
}
|
||||
ArrayIterator end() const {
|
||||
auto it = ArrayIterator(_slice);
|
||||
it._position = it._size;
|
||||
return it;
|
||||
}
|
||||
|
||||
inline Slice value () const {
|
||||
if (_position >= _size) {
|
||||
throw Exception(Exception::IndexOutOfBounds);
|
||||
}
|
||||
return operator*();
|
||||
}
|
||||
inline bool valid() const throw() { return (_position < _size); }
|
||||
|
||||
inline bool next () throw() {
|
||||
operator++();
|
||||
return valid();
|
||||
}
|
||||
|
||||
inline ValueLength index () const throw() {
|
||||
return _position;
|
||||
}
|
||||
|
||||
inline ValueLength size () const throw() {
|
||||
return _size;
|
||||
}
|
||||
inline Slice value() const {
|
||||
if (_position >= _size) {
|
||||
throw Exception(Exception::IndexOutOfBounds);
|
||||
}
|
||||
return operator*();
|
||||
}
|
||||
|
||||
inline bool isFirst () const throw() {
|
||||
return (_position == 0);
|
||||
}
|
||||
inline bool next() throw() {
|
||||
operator++();
|
||||
return valid();
|
||||
}
|
||||
|
||||
inline bool isLast () const throw() {
|
||||
return (_position + 1 >= _size);
|
||||
}
|
||||
inline ValueLength index() const throw() { return _position; }
|
||||
|
||||
private:
|
||||
inline ValueLength size() const throw() { return _size; }
|
||||
|
||||
Slice _slice;
|
||||
ValueLength _size;
|
||||
ValueLength _position;
|
||||
uint8_t const* _current;
|
||||
};
|
||||
inline bool isFirst() const throw() { return (_position == 0); }
|
||||
|
||||
class ObjectIterator {
|
||||
inline bool isLast() const throw() { return (_position + 1 >= _size); }
|
||||
|
||||
public:
|
||||
private:
|
||||
Slice _slice;
|
||||
ValueLength _size;
|
||||
ValueLength _position;
|
||||
uint8_t const* _current;
|
||||
};
|
||||
|
||||
struct ObjectPair {
|
||||
ObjectPair (Slice const& key, Slice const& value)
|
||||
: key(key), value(value) {
|
||||
}
|
||||
Slice const key;
|
||||
Slice const value;
|
||||
};
|
||||
class ObjectIterator {
|
||||
public:
|
||||
struct ObjectPair {
|
||||
ObjectPair(Slice const& key, Slice const& value) : key(key), value(value) {}
|
||||
Slice const key;
|
||||
Slice const value;
|
||||
};
|
||||
|
||||
ObjectIterator () = delete;
|
||||
ObjectIterator() = delete;
|
||||
|
||||
ObjectIterator (Slice const& slice)
|
||||
: _slice(slice), _size(_slice.length()), _position(0), _current(nullptr) {
|
||||
ObjectIterator(Slice const& slice)
|
||||
: _slice(slice), _size(_slice.length()), _position(0), _current(nullptr) {
|
||||
if (slice.type() != ValueType::Object) {
|
||||
throw Exception(Exception::InvalidValueType, "Expecting Object slice");
|
||||
}
|
||||
|
||||
if (slice.type() != ValueType::Object) {
|
||||
throw Exception(Exception::InvalidValueType, "Expecting Object slice");
|
||||
}
|
||||
if (slice.head() == 0x14 && slice.length() > 0) {
|
||||
_current = slice.keyAt(0).start();
|
||||
}
|
||||
}
|
||||
|
||||
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), _current(other._current) {
|
||||
}
|
||||
|
||||
ObjectIterator& operator= (ObjectIterator const& other) {
|
||||
_slice = other._slice;
|
||||
_size = other._size;
|
||||
_position = other._position;
|
||||
_current = other._current;
|
||||
return *this;
|
||||
}
|
||||
ObjectIterator(ObjectIterator const& other)
|
||||
: _slice(other._slice),
|
||||
_size(other._size),
|
||||
_position(other._position),
|
||||
_current(other._current) {}
|
||||
|
||||
// prefix ++
|
||||
ObjectIterator& operator++ () {
|
||||
++_position;
|
||||
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;
|
||||
}
|
||||
ObjectIterator& operator=(ObjectIterator const& other) {
|
||||
_slice = other._slice;
|
||||
_size = other._size;
|
||||
_position = other._position;
|
||||
_current = other._current;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// postfix ++
|
||||
ObjectIterator operator++ (int) {
|
||||
ObjectIterator result(*this);
|
||||
++(*this);
|
||||
return result;
|
||||
}
|
||||
// prefix ++
|
||||
ObjectIterator& operator++() {
|
||||
++_position;
|
||||
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;
|
||||
}
|
||||
|
||||
bool operator!= (ObjectIterator const& other) const {
|
||||
return _position != other._position;
|
||||
}
|
||||
// postfix ++
|
||||
ObjectIterator operator++(int) {
|
||||
ObjectIterator result(*this);
|
||||
++(*this);
|
||||
return result;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
bool operator!=(ObjectIterator const& other) const {
|
||||
return _position != other._position;
|
||||
}
|
||||
|
||||
ObjectIterator begin () {
|
||||
return ObjectIterator(_slice);
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
ObjectIterator begin () const {
|
||||
return ObjectIterator(_slice);
|
||||
}
|
||||
ObjectIterator begin() { return ObjectIterator(_slice); }
|
||||
|
||||
ObjectIterator end () {
|
||||
auto it = ObjectIterator(_slice);
|
||||
it._position = it._size;
|
||||
return it;
|
||||
}
|
||||
ObjectIterator begin() const { return ObjectIterator(_slice); }
|
||||
|
||||
ObjectIterator end () const {
|
||||
auto it = ObjectIterator(_slice);
|
||||
it._position = it._size;
|
||||
return it;
|
||||
}
|
||||
ObjectIterator end() {
|
||||
auto it = ObjectIterator(_slice);
|
||||
it._position = it._size;
|
||||
return it;
|
||||
}
|
||||
|
||||
inline bool valid () const throw() {
|
||||
return (_position < _size);
|
||||
}
|
||||
|
||||
inline Slice key () const {
|
||||
if (_position >= _size) {
|
||||
throw Exception(Exception::IndexOutOfBounds);
|
||||
}
|
||||
if (_current != nullptr) {
|
||||
return Slice(_current, _slice.options);
|
||||
}
|
||||
return _slice.keyAt(_position);
|
||||
}
|
||||
ObjectIterator end() const {
|
||||
auto it = ObjectIterator(_slice);
|
||||
it._position = it._size;
|
||||
return it;
|
||||
}
|
||||
|
||||
inline Slice value () const {
|
||||
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 valid() const throw() { return (_position < _size); }
|
||||
|
||||
inline bool next () throw() {
|
||||
operator++();
|
||||
return valid();
|
||||
}
|
||||
inline Slice key() const {
|
||||
if (_position >= _size) {
|
||||
throw Exception(Exception::IndexOutOfBounds);
|
||||
}
|
||||
if (_current != nullptr) {
|
||||
return Slice(_current, _slice.options);
|
||||
}
|
||||
return _slice.keyAt(_position);
|
||||
}
|
||||
|
||||
inline ValueLength index () const throw() {
|
||||
return _position;
|
||||
}
|
||||
|
||||
inline ValueLength size () const throw() {
|
||||
return _size;
|
||||
}
|
||||
inline Slice value() const {
|
||||
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 isFirst () const throw() {
|
||||
return (_position == 0);
|
||||
}
|
||||
inline bool next() throw() {
|
||||
operator++();
|
||||
return valid();
|
||||
}
|
||||
|
||||
inline bool isLast () const throw() {
|
||||
return (_position + 1 >= _size);
|
||||
}
|
||||
inline ValueLength index() const throw() { return _position; }
|
||||
|
||||
private:
|
||||
inline ValueLength size() const throw() { return _size; }
|
||||
|
||||
Slice _slice;
|
||||
ValueLength _size;
|
||||
ValueLength _position;
|
||||
uint8_t const* _current;
|
||||
};
|
||||
inline bool isFirst() const throw() { return (_position == 0); }
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
inline bool isLast() const throw() { return (_position + 1 >= _size); }
|
||||
|
||||
private:
|
||||
Slice _slice;
|
||||
ValueLength _size;
|
||||
ValueLength _position;
|
||||
uint8_t const* _current;
|
||||
};
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
std::ostream& operator<< (std::ostream&, arangodb::velocypack::ArrayIterator const*);
|
||||
|
||||
std::ostream& operator<< (std::ostream&, arangodb::velocypack::ArrayIterator const&);
|
||||
|
||||
std::ostream& operator<< (std::ostream&, arangodb::velocypack::ObjectIterator const*);
|
||||
std::ostream& operator<<(std::ostream&,
|
||||
arangodb::velocypack::ArrayIterator const*);
|
||||
|
||||
std::ostream& operator<< (std::ostream&, arangodb::velocypack::ObjectIterator const&);
|
||||
std::ostream& operator<<(std::ostream&,
|
||||
arangodb::velocypack::ArrayIterator const&);
|
||||
|
||||
std::ostream& operator<<(std::ostream&,
|
||||
arangodb::velocypack::ObjectIterator const*);
|
||||
|
||||
std::ostream& operator<<(std::ostream&,
|
||||
arangodb::velocypack::ObjectIterator const&);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,81 +33,83 @@
|
|||
#include "velocypack/velocypack-common.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
class AttributeTranslator;
|
||||
class Dumper;
|
||||
class Slice;
|
||||
namespace velocypack {
|
||||
class AttributeTranslator;
|
||||
class Dumper;
|
||||
class Slice;
|
||||
|
||||
struct AttributeExcludeHandler {
|
||||
virtual ~AttributeExcludeHandler () {
|
||||
}
|
||||
struct AttributeExcludeHandler {
|
||||
virtual ~AttributeExcludeHandler() {}
|
||||
|
||||
virtual bool shouldExclude (Slice const& key, int nesting) = 0;
|
||||
};
|
||||
|
||||
struct CustomTypeHandler {
|
||||
virtual ~CustomTypeHandler () {
|
||||
}
|
||||
virtual bool shouldExclude(Slice const& key, int nesting) = 0;
|
||||
};
|
||||
|
||||
virtual void toJson (Slice const& value, Dumper* dumper, Slice const& base) = 0;
|
||||
virtual ValueLength byteSize (Slice const& value) = 0;
|
||||
};
|
||||
|
||||
struct Options {
|
||||
enum UnsupportedTypeBehavior {
|
||||
NullifyUnsupportedType,
|
||||
FailOnUnsupportedType
|
||||
};
|
||||
struct CustomTypeHandler {
|
||||
virtual ~CustomTypeHandler() {}
|
||||
|
||||
Options () {
|
||||
}
|
||||
|
||||
// Dumper behavior when a VPack value is serialized to JSON that
|
||||
// has no JSON equivalent
|
||||
UnsupportedTypeBehavior unsupportedTypeBehavior = FailOnUnsupportedType;
|
||||
|
||||
// callback for excluding attributes from being built by the Parser
|
||||
AttributeExcludeHandler* attributeExcludeHandler = nullptr;
|
||||
virtual void toJson(Slice const& value, Dumper* dumper,
|
||||
Slice const& base) = 0;
|
||||
virtual ValueLength byteSize(Slice const& value) = 0;
|
||||
};
|
||||
|
||||
AttributeTranslator* attributeTranslator = nullptr;
|
||||
struct Options {
|
||||
enum UnsupportedTypeBehavior {
|
||||
NullifyUnsupportedType,
|
||||
FailOnUnsupportedType
|
||||
};
|
||||
|
||||
// custom type handler used for processing custom types by Dumper and Slicer
|
||||
CustomTypeHandler* customTypeHandler = nullptr;
|
||||
Options() {}
|
||||
|
||||
// allow building Arrays without index table?
|
||||
bool buildUnindexedArrays = false;
|
||||
// Dumper behavior when a VPack value is serialized to JSON that
|
||||
// has no JSON equivalent
|
||||
UnsupportedTypeBehavior unsupportedTypeBehavior = FailOnUnsupportedType;
|
||||
|
||||
// allow building Objects without index table?
|
||||
bool buildUnindexedObjects = false;
|
||||
// callback for excluding attributes from being built by the Parser
|
||||
AttributeExcludeHandler* attributeExcludeHandler = nullptr;
|
||||
|
||||
// pretty-print JSON output when dumping with Dumper
|
||||
bool prettyPrint = false;
|
||||
|
||||
// keep top-level object/array open when building objects with the Parser
|
||||
bool keepTopLevelOpen = false;
|
||||
AttributeTranslator* attributeTranslator = nullptr;
|
||||
|
||||
// validate UTF-8 strings when JSON-parsing with Parser
|
||||
bool validateUtf8Strings = false;
|
||||
// custom type handler used for processing custom types by Dumper and Slicer
|
||||
CustomTypeHandler* customTypeHandler = nullptr;
|
||||
|
||||
// validate that attribute names in Object values are actually
|
||||
// unique when creating objects via Builder. This also includes
|
||||
// creation of Object values via a Parser
|
||||
bool checkAttributeUniqueness = false;
|
||||
// allow building Arrays without index table?
|
||||
bool buildUnindexedArrays = false;
|
||||
|
||||
// whether or not attribute names should be sorted in Object
|
||||
// values created with a Builder. This also includes creation of
|
||||
// Object values via a Parser
|
||||
bool sortAttributeNames = true;
|
||||
// allow building Objects without index table?
|
||||
bool buildUnindexedObjects = false;
|
||||
|
||||
// escape forward slashes when serializing VPack values into
|
||||
// JSON with a Dumper
|
||||
bool escapeForwardSlashes = false;
|
||||
// pretty-print JSON output when dumping with Dumper
|
||||
bool prettyPrint = false;
|
||||
|
||||
// default options with the above settings
|
||||
static Options Defaults;
|
||||
};
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
// keep top-level object/array open when building objects with the Parser
|
||||
bool keepTopLevelOpen = false;
|
||||
|
||||
// validate UTF-8 strings when JSON-parsing with Parser
|
||||
bool validateUtf8Strings = false;
|
||||
|
||||
// validate that attribute names in Object values are actually
|
||||
// unique when creating objects via Builder. This also includes
|
||||
// creation of Object values via a Parser
|
||||
bool checkAttributeUniqueness = false;
|
||||
|
||||
// whether or not attribute names should be sorted in Object
|
||||
// values created with a Builder. This also includes creation of
|
||||
// Object values via a Parser
|
||||
bool sortAttributeNames = true;
|
||||
|
||||
// escape forward slashes when serializing VPack values into
|
||||
// JSON with a Dumper
|
||||
bool escapeForwardSlashes = false;
|
||||
|
||||
// disallow using type External (to prevent injection of arbitrary pointer
|
||||
// values as a security precaution)
|
||||
bool disallowExternals = false;
|
||||
|
||||
// default options with the above settings
|
||||
static Options Defaults;
|
||||
};
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,252 +38,231 @@
|
|||
#include "velocypack/ValueType.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
namespace velocypack {
|
||||
|
||||
class Parser {
|
||||
class Parser {
|
||||
// This class can parse JSON very rapidly, but only from contiguous
|
||||
// blocks of memory. It builds the result using the Builder.
|
||||
|
||||
// This class can parse JSON very rapidly, but only from contiguous
|
||||
// blocks of memory. It builds the result using the Builder.
|
||||
struct ParsedNumber {
|
||||
ParsedNumber() : intValue(0), doubleValue(0.0), isInteger(true) {}
|
||||
|
||||
struct ParsedNumber {
|
||||
ParsedNumber ()
|
||||
: intValue(0),
|
||||
doubleValue(0.0),
|
||||
isInteger(true) {
|
||||
}
|
||||
|
||||
void addDigit (int i) {
|
||||
if (isInteger) {
|
||||
// check if adding another digit to the int will make it overflow
|
||||
if (intValue < 1844674407370955161ULL ||
|
||||
(intValue == 1844674407370955161ULL && (i - '0') <= 5)) {
|
||||
// int won't overflow
|
||||
intValue = intValue * 10 + (i - '0');
|
||||
return;
|
||||
}
|
||||
// int would overflow
|
||||
doubleValue = static_cast<double>(intValue);
|
||||
isInteger = false;
|
||||
}
|
||||
|
||||
doubleValue = doubleValue * 10.0 + (i - '0');
|
||||
if (std::isnan(doubleValue) || ! std::isfinite(doubleValue)) {
|
||||
throw Exception(Exception::NumberOutOfRange);
|
||||
}
|
||||
}
|
||||
|
||||
double asDouble () const {
|
||||
if (isInteger) {
|
||||
return static_cast<double>(intValue);
|
||||
}
|
||||
return doubleValue;
|
||||
}
|
||||
|
||||
uint64_t intValue;
|
||||
double doubleValue;
|
||||
bool isInteger;
|
||||
};
|
||||
|
||||
Builder _b;
|
||||
uint8_t const* _start;
|
||||
size_t _size;
|
||||
size_t _pos;
|
||||
int _nesting;
|
||||
|
||||
public:
|
||||
|
||||
Options const* options;
|
||||
|
||||
Parser (Parser const&) = delete;
|
||||
Parser& operator= (Parser const&) = delete;
|
||||
|
||||
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");
|
||||
}
|
||||
_b.options = options;
|
||||
void addDigit(int i) {
|
||||
if (isInteger) {
|
||||
// check if adding another digit to the int will make it overflow
|
||||
if (intValue < 1844674407370955161ULL ||
|
||||
(intValue == 1844674407370955161ULL && (i - '0') <= 5)) {
|
||||
// int won't overflow
|
||||
intValue = intValue * 10 + (i - '0');
|
||||
return;
|
||||
}
|
||||
// int would overflow
|
||||
doubleValue = static_cast<double>(intValue);
|
||||
isInteger = false;
|
||||
}
|
||||
|
||||
static Builder fromJson (std::string const& json, Options const* options = &Options::Defaults) {
|
||||
Parser parser(options);
|
||||
parser.parse(json);
|
||||
return parser.steal();
|
||||
}
|
||||
|
||||
static Builder fromJson (uint8_t const* start, size_t size, Options const* options = &Options::Defaults) {
|
||||
Parser parser(options);
|
||||
parser.parse(start, size);
|
||||
return parser.steal();
|
||||
}
|
||||
doubleValue = doubleValue * 10.0 + (i - '0');
|
||||
if (std::isnan(doubleValue) || !std::isfinite(doubleValue)) {
|
||||
throw Exception(Exception::NumberOutOfRange);
|
||||
}
|
||||
}
|
||||
|
||||
ValueLength parse (std::string const& json, bool multi = false) {
|
||||
return parse(reinterpret_cast<uint8_t const*>(json.c_str()), json.size(), multi);
|
||||
}
|
||||
double asDouble() const {
|
||||
if (isInteger) {
|
||||
return static_cast<double>(intValue);
|
||||
}
|
||||
return doubleValue;
|
||||
}
|
||||
|
||||
ValueLength parse (char const* start, size_t size,
|
||||
bool multi = false) {
|
||||
return parse(reinterpret_cast<uint8_t const*>(start), size, multi);
|
||||
}
|
||||
uint64_t intValue;
|
||||
double doubleValue;
|
||||
bool isInteger;
|
||||
};
|
||||
|
||||
ValueLength parse (uint8_t const* start, size_t size,
|
||||
bool multi = false) {
|
||||
_start = start;
|
||||
_size = size;
|
||||
_pos = 0;
|
||||
_b.clear();
|
||||
_b.options = options;
|
||||
return parseInternal(multi);
|
||||
}
|
||||
Builder _b;
|
||||
uint8_t const* _start;
|
||||
size_t _size;
|
||||
size_t _pos;
|
||||
int _nesting;
|
||||
|
||||
// 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);
|
||||
}
|
||||
public:
|
||||
Options const* options;
|
||||
|
||||
// Beware, only valid as long as you do not parse more, use steal
|
||||
// to move the data out!
|
||||
uint8_t const* start () {
|
||||
return _b.start();
|
||||
}
|
||||
Parser(Parser const&) = delete;
|
||||
Parser& operator=(Parser const&) = delete;
|
||||
|
||||
// Returns the position at the time when the just reported error
|
||||
// occurred, only use when handling an exception.
|
||||
size_t errorPos () const {
|
||||
return _pos > 0 ? _pos - 1 : _pos;
|
||||
}
|
||||
Parser(Options const* options = &Options::Defaults)
|
||||
: _start(nullptr), _size(0), _pos(0), _nesting(0), options(options) {
|
||||
VELOCYPACK_ASSERT(options != nullptr);
|
||||
|
||||
void clear () {
|
||||
_b.clear();
|
||||
}
|
||||
if (options == nullptr) {
|
||||
throw Exception(Exception::InternalError, "Options cannot be a nullptr");
|
||||
}
|
||||
_b.options = options;
|
||||
}
|
||||
|
||||
private:
|
||||
static Builder fromJson(std::string const& json,
|
||||
Options const* options = &Options::Defaults) {
|
||||
Parser parser(options);
|
||||
parser.parse(json);
|
||||
return parser.steal();
|
||||
}
|
||||
|
||||
inline int peek () const {
|
||||
if (_pos >= _size) {
|
||||
return -1;
|
||||
}
|
||||
return static_cast<int>(_start[_pos]);
|
||||
}
|
||||
static Builder fromJson(uint8_t const* start, size_t size,
|
||||
Options const* options = &Options::Defaults) {
|
||||
Parser parser(options);
|
||||
parser.parse(start, size);
|
||||
return parser.steal();
|
||||
}
|
||||
|
||||
inline int consume () {
|
||||
if (_pos >= _size) {
|
||||
return -1;
|
||||
}
|
||||
return static_cast<int>(_start[_pos++]);
|
||||
}
|
||||
ValueLength parse(std::string const& json, bool multi = false) {
|
||||
return parse(reinterpret_cast<uint8_t const*>(json.c_str()), json.size(),
|
||||
multi);
|
||||
}
|
||||
|
||||
inline void unconsume () {
|
||||
--_pos;
|
||||
}
|
||||
ValueLength parse(char const* start, size_t size, bool multi = false) {
|
||||
return parse(reinterpret_cast<uint8_t const*>(start), size, multi);
|
||||
}
|
||||
|
||||
inline void reset () {
|
||||
_pos = 0;
|
||||
}
|
||||
ValueLength parse(uint8_t const* start, size_t size, bool multi = false) {
|
||||
_start = start;
|
||||
_size = size;
|
||||
_pos = 0;
|
||||
_b.clear();
|
||||
_b.options = options;
|
||||
return parseInternal(multi);
|
||||
}
|
||||
|
||||
ValueLength parseInternal (bool multi);
|
||||
// We probably want a parse from stream at some stage...
|
||||
// Not with this high-performance two-pass approach. :-(
|
||||
|
||||
inline bool isWhiteSpace (uint8_t i) const throw() {
|
||||
return (i == ' ' || i == '\t' || i == '\n' || i == '\r');
|
||||
}
|
||||
Builder&& steal() {
|
||||
if (_b._buffer == nullptr) {
|
||||
throw Exception(Exception::InternalError,
|
||||
"Buffer of Builder is already gone");
|
||||
}
|
||||
return std::move(_b);
|
||||
}
|
||||
|
||||
// skips over all following whitespace tokens but does not consume the
|
||||
// byte following the whitespace
|
||||
int skipWhiteSpace (char const*);
|
||||
// Beware, only valid as long as you do not parse more, use steal
|
||||
// to move the data out!
|
||||
uint8_t const* start() { return _b.start(); }
|
||||
|
||||
void parseTrue () {
|
||||
// Called, when main mode has just seen a 't', need to see "rue" next
|
||||
if (consume() != 'r' || consume() != 'u' || consume() != 'e') {
|
||||
throw Exception(Exception::ParseError, "Expecting 'true'");
|
||||
}
|
||||
_b.addTrue();
|
||||
}
|
||||
// Returns the position at the time when the just reported error
|
||||
// occurred, only use when handling an exception.
|
||||
size_t errorPos() const { return _pos > 0 ? _pos - 1 : _pos; }
|
||||
|
||||
void parseFalse () {
|
||||
// Called, when main mode has just seen a 'f', need to see "alse" next
|
||||
if (consume() != 'a' || consume() != 'l' || consume() != 's' ||
|
||||
consume() != 'e') {
|
||||
throw Exception(Exception::ParseError, "Expecting 'false'");
|
||||
}
|
||||
_b.addFalse();
|
||||
}
|
||||
void clear() { _b.clear(); }
|
||||
|
||||
void parseNull () {
|
||||
// Called, when main mode has just seen a 'n', need to see "ull" next
|
||||
if (consume() != 'u' || consume() != 'l' || consume() != 'l') {
|
||||
throw Exception(Exception::ParseError, "Expecting 'null'");
|
||||
}
|
||||
_b.addNull();
|
||||
}
|
||||
|
||||
void scanDigits (ParsedNumber& value) {
|
||||
while (true) {
|
||||
int i = consume();
|
||||
if (i < 0) {
|
||||
return;
|
||||
}
|
||||
if (i < '0' || i > '9') {
|
||||
unconsume();
|
||||
return;
|
||||
}
|
||||
value.addDigit(i);
|
||||
}
|
||||
}
|
||||
private:
|
||||
inline int peek() const {
|
||||
if (_pos >= _size) {
|
||||
return -1;
|
||||
}
|
||||
return static_cast<int>(_start[_pos]);
|
||||
}
|
||||
|
||||
double scanDigitsFractional () {
|
||||
double pot = 0.1;
|
||||
double x = 0.0;
|
||||
while (true) {
|
||||
int i = consume();
|
||||
if (i < 0) {
|
||||
return x;
|
||||
}
|
||||
if (i < '0' || i > '9') {
|
||||
unconsume();
|
||||
return x;
|
||||
}
|
||||
x = x + pot * (i - '0');
|
||||
pot /= 10.0;
|
||||
}
|
||||
}
|
||||
inline int consume() {
|
||||
if (_pos >= _size) {
|
||||
return -1;
|
||||
}
|
||||
return static_cast<int>(_start[_pos++]);
|
||||
}
|
||||
|
||||
inline int getOneOrThrow (char const* msg) {
|
||||
int i = consume();
|
||||
if (i < 0) {
|
||||
throw Exception(Exception::ParseError, msg);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
inline void unconsume() { --_pos; }
|
||||
|
||||
inline void increaseNesting () {
|
||||
++_nesting;
|
||||
}
|
||||
|
||||
inline void decreaseNesting () {
|
||||
--_nesting;
|
||||
}
|
||||
inline void reset() { _pos = 0; }
|
||||
|
||||
void parseNumber ();
|
||||
ValueLength parseInternal(bool multi);
|
||||
|
||||
void parseString ();
|
||||
inline bool isWhiteSpace(uint8_t i) const throw() {
|
||||
return (i == ' ' || i == '\t' || i == '\n' || i == '\r');
|
||||
}
|
||||
|
||||
void parseArray ();
|
||||
// skips over all following whitespace tokens but does not consume the
|
||||
// byte following the whitespace
|
||||
int skipWhiteSpace(char const*);
|
||||
|
||||
void parseObject ();
|
||||
void parseTrue() {
|
||||
// Called, when main mode has just seen a 't', need to see "rue" next
|
||||
if (consume() != 'r' || consume() != 'u' || consume() != 'e') {
|
||||
throw Exception(Exception::ParseError, "Expecting 'true'");
|
||||
}
|
||||
_b.addTrue();
|
||||
}
|
||||
|
||||
void parseJson ();
|
||||
void parseFalse() {
|
||||
// Called, when main mode has just seen a 'f', need to see "alse" next
|
||||
if (consume() != 'a' || consume() != 'l' || consume() != 's' ||
|
||||
consume() != 'e') {
|
||||
throw Exception(Exception::ParseError, "Expecting 'false'");
|
||||
}
|
||||
_b.addFalse();
|
||||
}
|
||||
|
||||
};
|
||||
void parseNull() {
|
||||
// Called, when main mode has just seen a 'n', need to see "ull" next
|
||||
if (consume() != 'u' || consume() != 'l' || consume() != 'l') {
|
||||
throw Exception(Exception::ParseError, "Expecting 'null'");
|
||||
}
|
||||
_b.addNull();
|
||||
}
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
void scanDigits(ParsedNumber& value) {
|
||||
while (true) {
|
||||
int i = consume();
|
||||
if (i < 0) {
|
||||
return;
|
||||
}
|
||||
if (i < '0' || i > '9') {
|
||||
unconsume();
|
||||
return;
|
||||
}
|
||||
value.addDigit(i);
|
||||
}
|
||||
}
|
||||
|
||||
double scanDigitsFractional() {
|
||||
double pot = 0.1;
|
||||
double x = 0.0;
|
||||
while (true) {
|
||||
int i = consume();
|
||||
if (i < 0) {
|
||||
return x;
|
||||
}
|
||||
if (i < '0' || i > '9') {
|
||||
unconsume();
|
||||
return x;
|
||||
}
|
||||
x = x + pot * (i - '0');
|
||||
pot /= 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
inline int getOneOrThrow(char const* msg) {
|
||||
int i = consume();
|
||||
if (i < 0) {
|
||||
throw Exception(Exception::ParseError, msg);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
inline void increaseNesting() { ++_nesting; }
|
||||
|
||||
inline void decreaseNesting() { --_nesting; }
|
||||
|
||||
void parseNumber();
|
||||
|
||||
void parseString();
|
||||
|
||||
void parseArray();
|
||||
|
||||
void parseObject();
|
||||
|
||||
void parseJson();
|
||||
};
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,117 +35,90 @@
|
|||
#include "velocypack/Buffer.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
namespace velocypack {
|
||||
|
||||
struct Sink {
|
||||
Sink () {
|
||||
}
|
||||
Sink (Sink const&) = delete;
|
||||
Sink& operator= (Sink const&) = delete;
|
||||
struct Sink {
|
||||
Sink() {}
|
||||
Sink(Sink const&) = delete;
|
||||
Sink& operator=(Sink const&) = delete;
|
||||
|
||||
virtual ~Sink () {
|
||||
}
|
||||
virtual void push_back (char c) = 0;
|
||||
virtual void append (std::string const& p) = 0;
|
||||
virtual void append (char const* p) = 0;
|
||||
virtual void append (char const* p, ValueLength len) = 0;
|
||||
virtual void reserve (ValueLength len) = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ByteBufferSinkImpl final : public Sink {
|
||||
explicit ByteBufferSinkImpl (Buffer<T>* buffer)
|
||||
: buffer(buffer) {
|
||||
}
|
||||
virtual ~Sink() {}
|
||||
virtual void push_back(char c) = 0;
|
||||
virtual void append(std::string const& p) = 0;
|
||||
virtual void append(char const* p) = 0;
|
||||
virtual void append(char const* p, ValueLength len) = 0;
|
||||
virtual void reserve(ValueLength len) = 0;
|
||||
};
|
||||
|
||||
void push_back (char c) override final {
|
||||
buffer->push_back(c);
|
||||
}
|
||||
template <typename T>
|
||||
struct ByteBufferSinkImpl final : public Sink {
|
||||
explicit ByteBufferSinkImpl(Buffer<T>* buffer) : buffer(buffer) {}
|
||||
|
||||
void append (std::string const& p) override final {
|
||||
buffer->append(p.c_str(), p.size());
|
||||
}
|
||||
void push_back(char c) override final { buffer->push_back(c); }
|
||||
|
||||
void append (char const* p) override final {
|
||||
buffer->append(p, strlen(p));
|
||||
}
|
||||
void append(std::string const& p) override final {
|
||||
buffer->append(p.c_str(), p.size());
|
||||
}
|
||||
|
||||
void append (char const* p, ValueLength len) override final {
|
||||
buffer->append(p, len);
|
||||
}
|
||||
void append(char const* p) override final { buffer->append(p, strlen(p)); }
|
||||
|
||||
void reserve (ValueLength len) override final {
|
||||
buffer->reserve(len);
|
||||
}
|
||||
void append(char const* p, ValueLength len) override final {
|
||||
buffer->append(p, len);
|
||||
}
|
||||
|
||||
Buffer<T>* buffer;
|
||||
};
|
||||
|
||||
typedef ByteBufferSinkImpl<char> CharBufferSink;
|
||||
void reserve(ValueLength len) override final { buffer->reserve(len); }
|
||||
|
||||
template<typename T>
|
||||
struct StringSinkImpl final : public Sink {
|
||||
explicit StringSinkImpl (T* buffer)
|
||||
: buffer(buffer) {
|
||||
}
|
||||
Buffer<T>* buffer;
|
||||
};
|
||||
|
||||
void push_back (char c) override final {
|
||||
buffer->push_back(c);
|
||||
}
|
||||
typedef ByteBufferSinkImpl<char> CharBufferSink;
|
||||
|
||||
void append (std::string const& p) override final {
|
||||
buffer->append(p);
|
||||
}
|
||||
template <typename T>
|
||||
struct StringSinkImpl final : public Sink {
|
||||
explicit StringSinkImpl(T* buffer) : buffer(buffer) {}
|
||||
|
||||
void append (char const* p) override final {
|
||||
buffer->append(p, strlen(p));
|
||||
}
|
||||
void push_back(char c) override final { buffer->push_back(c); }
|
||||
|
||||
void append (char const* p, ValueLength len) override final {
|
||||
buffer->append(p, len);
|
||||
}
|
||||
void append(std::string const& p) override final { buffer->append(p); }
|
||||
|
||||
void reserve (ValueLength len) override final {
|
||||
buffer->reserve(len);
|
||||
}
|
||||
void append(char const* p) override final { buffer->append(p, strlen(p)); }
|
||||
|
||||
T* buffer;
|
||||
};
|
||||
|
||||
typedef StringSinkImpl<std::string> StringSink;
|
||||
void append(char const* p, ValueLength len) override final {
|
||||
buffer->append(p, len);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct StreamSinkImpl final : public Sink {
|
||||
explicit StreamSinkImpl (T* stream)
|
||||
: stream(stream) {
|
||||
}
|
||||
void reserve(ValueLength len) override final { buffer->reserve(len); }
|
||||
|
||||
void push_back (char c) override final {
|
||||
*stream << c;
|
||||
}
|
||||
T* buffer;
|
||||
};
|
||||
|
||||
void append (std::string const& p) override final {
|
||||
*stream << p;
|
||||
}
|
||||
typedef StringSinkImpl<std::string> StringSink;
|
||||
|
||||
void append (char const* p) override final {
|
||||
stream->write(p, static_cast<std::streamsize>(strlen(p)));
|
||||
}
|
||||
template <typename T>
|
||||
struct StreamSinkImpl final : public Sink {
|
||||
explicit StreamSinkImpl(T* stream) : stream(stream) {}
|
||||
|
||||
void append (char const* p, ValueLength len) override final {
|
||||
stream->write(p, static_cast<std::streamsize>(len));
|
||||
}
|
||||
void push_back(char c) override final { *stream << c; }
|
||||
|
||||
void reserve (ValueLength) override final {
|
||||
}
|
||||
void append(std::string const& p) override final { *stream << p; }
|
||||
|
||||
T* stream;
|
||||
};
|
||||
|
||||
typedef StreamSinkImpl<std::ostringstream> StringStreamSink;
|
||||
typedef StreamSinkImpl<std::ofstream> OutputFileStreamSink;
|
||||
void append(char const* p) override final {
|
||||
stream->write(p, static_cast<std::streamsize>(strlen(p)));
|
||||
}
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
void append(char const* p, ValueLength len) override final {
|
||||
stream->write(p, static_cast<std::streamsize>(len));
|
||||
}
|
||||
|
||||
void reserve(ValueLength) override final {}
|
||||
|
||||
T* stream;
|
||||
};
|
||||
|
||||
typedef StreamSinkImpl<std::ostringstream> StringStreamSink;
|
||||
typedef StreamSinkImpl<std::ofstream> OutputFileStreamSink;
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -34,215 +34,190 @@
|
|||
#include "velocypack/ValueType.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
namespace velocypack {
|
||||
|
||||
class Value {
|
||||
// Convenience class for more compact notation
|
||||
class Value {
|
||||
// Convenience class for more compact notation
|
||||
|
||||
friend class Builder;
|
||||
friend class Builder;
|
||||
|
||||
public:
|
||||
public:
|
||||
enum class CType {
|
||||
None = 0,
|
||||
Bool = 1,
|
||||
Double = 2,
|
||||
Int64 = 3,
|
||||
UInt64 = 4,
|
||||
String = 5,
|
||||
CharPtr = 6,
|
||||
VoidPtr = 7
|
||||
};
|
||||
|
||||
enum class CType {
|
||||
None = 0,
|
||||
Bool = 1,
|
||||
Double = 2,
|
||||
Int64 = 3,
|
||||
UInt64 = 4,
|
||||
String = 5,
|
||||
CharPtr = 6,
|
||||
VoidPtr = 7
|
||||
};
|
||||
|
||||
private:
|
||||
private:
|
||||
ValueType _valueType;
|
||||
CType _cType; // denotes variant used, 0: none
|
||||
|
||||
ValueType _valueType;
|
||||
CType _cType; // denotes variant used, 0: none
|
||||
union {
|
||||
bool b; // 1: bool
|
||||
double d; // 2: double
|
||||
int64_t i; // 3: int64_t
|
||||
uint64_t u; // 4: uint64_t
|
||||
std::string const* s; // 5: std::string
|
||||
char const* c; // 6: char const*
|
||||
void const* e; // external
|
||||
} _value;
|
||||
|
||||
union {
|
||||
bool b; // 1: bool
|
||||
double d; // 2: double
|
||||
int64_t i; // 3: int64_t
|
||||
uint64_t u; // 4: uint64_t
|
||||
std::string const* s; // 5: std::string
|
||||
char const* c; // 6: char const*
|
||||
void const* e; // external
|
||||
}
|
||||
_value;
|
||||
|
||||
bool _unindexed;
|
||||
|
||||
public:
|
||||
bool _unindexed;
|
||||
|
||||
public:
|
||||
#ifdef SWIG
|
||||
Value () : _valueType(ValueType::None), _cType(CType::None),
|
||||
_unindexed(false) {
|
||||
}
|
||||
Value()
|
||||
: _valueType(ValueType::None), _cType(CType::None), _unindexed(false) {}
|
||||
#else
|
||||
Value () = delete;
|
||||
Value() = delete;
|
||||
#endif
|
||||
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
// 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), _unindexed(false) {
|
||||
_value.b = b;
|
||||
}
|
||||
explicit Value(bool b, ValueType t = ValueType::Bool)
|
||||
: _valueType(t), _cType(CType::Bool), _unindexed(false) {
|
||||
_value.b = b;
|
||||
}
|
||||
|
||||
explicit Value (double d, ValueType t = ValueType::Double)
|
||||
: _valueType(t), _cType(CType::Double), _unindexed(false) {
|
||||
_value.d = d;
|
||||
}
|
||||
explicit Value(double d, ValueType t = ValueType::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), _unindexed(false) {
|
||||
_value.e = e;
|
||||
}
|
||||
explicit Value(void const* e, ValueType t = ValueType::External)
|
||||
: _valueType(t), _cType(CType::VoidPtr), _unindexed(false) {
|
||||
_value.e = e;
|
||||
}
|
||||
|
||||
explicit Value (char const* c, ValueType t = ValueType::String)
|
||||
: _valueType(t), _cType(CType::CharPtr), _unindexed(false) {
|
||||
_value.c = c;
|
||||
}
|
||||
explicit Value(char const* c, ValueType t = ValueType::String)
|
||||
: _valueType(t), _cType(CType::CharPtr), _unindexed(false) {
|
||||
_value.c = c;
|
||||
}
|
||||
|
||||
explicit Value (int32_t i, ValueType t = ValueType::Int)
|
||||
: _valueType(t), _cType(CType::Int64), _unindexed(false) {
|
||||
_value.i = static_cast<int64_t>(i);
|
||||
}
|
||||
explicit Value(int32_t i, ValueType t = ValueType::Int)
|
||||
: _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), _unindexed(false) {
|
||||
_value.u = static_cast<uint64_t>(u);
|
||||
}
|
||||
explicit Value(uint32_t u, ValueType t = ValueType::UInt)
|
||||
: _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), _unindexed(false) {
|
||||
_value.i = i;
|
||||
}
|
||||
explicit Value(int64_t i, ValueType t = ValueType::Int)
|
||||
: _valueType(t), _cType(CType::Int64), _unindexed(false) {
|
||||
_value.i = i;
|
||||
}
|
||||
|
||||
explicit Value (uint64_t u, ValueType t = ValueType::UInt)
|
||||
: _valueType(t), _cType(CType::UInt64), _unindexed(false) {
|
||||
_value.u = u;
|
||||
}
|
||||
explicit Value(uint64_t u, ValueType t = ValueType::UInt)
|
||||
: _valueType(t), _cType(CType::UInt64), _unindexed(false) {
|
||||
_value.u = u;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
// MacOS uses the following typedefs:
|
||||
// - typedef unsigned int uint32_t;
|
||||
// - typedef unsigned long long uint64_t;
|
||||
// - typedef unsigned long size_t;
|
||||
// not defining the method for type unsigned long will prevent
|
||||
// users from constructing Value objects with a size_t input
|
||||
#ifdef __APPLE__
|
||||
// MacOS uses the following typedefs:
|
||||
// - typedef unsigned int uint32_t;
|
||||
// - typedef unsigned long long uint64_t;
|
||||
// - typedef unsigned long size_t;
|
||||
// not defining the method for type unsigned long will prevent
|
||||
// users from constructing Value objects with a size_t input
|
||||
|
||||
// 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), _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), _unindexed(false) {
|
||||
_value.s = &s;
|
||||
}
|
||||
// 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), _unindexed(false) {
|
||||
_value.i = static_cast<uint64_t>(i);
|
||||
}
|
||||
#endif
|
||||
|
||||
ValueType valueType () const {
|
||||
return _valueType;
|
||||
}
|
||||
explicit Value(std::string const& s, ValueType t = ValueType::String)
|
||||
: _valueType(t), _cType(CType::String), _unindexed(false) {
|
||||
_value.s = &s;
|
||||
}
|
||||
|
||||
CType cType () const {
|
||||
return _cType;
|
||||
}
|
||||
ValueType valueType() const { return _valueType; }
|
||||
|
||||
bool isString () const {
|
||||
return _valueType == ValueType::String;
|
||||
}
|
||||
CType cType() const { return _cType; }
|
||||
|
||||
bool getBool () const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::Bool);
|
||||
return _value.b;
|
||||
}
|
||||
bool isString() const { return _valueType == ValueType::String; }
|
||||
|
||||
double getDouble () const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::Double);
|
||||
return _value.d;
|
||||
}
|
||||
bool getBool() const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::Bool);
|
||||
return _value.b;
|
||||
}
|
||||
|
||||
int64_t getInt64 () const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::Int64);
|
||||
return _value.i;
|
||||
}
|
||||
double getDouble() const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::Double);
|
||||
return _value.d;
|
||||
}
|
||||
|
||||
uint64_t getUInt64 () const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::UInt64);
|
||||
return _value.u;
|
||||
}
|
||||
int64_t getInt64() const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::Int64);
|
||||
return _value.i;
|
||||
}
|
||||
|
||||
std::string const* getString () const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::String);
|
||||
return _value.s;
|
||||
}
|
||||
uint64_t getUInt64() const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::UInt64);
|
||||
return _value.u;
|
||||
}
|
||||
|
||||
void const* getExternal () const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::VoidPtr);
|
||||
return _value.e;
|
||||
}
|
||||
std::string const* getString() const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::String);
|
||||
return _value.s;
|
||||
}
|
||||
|
||||
char const* getCharPtr () const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::CharPtr);
|
||||
return _value.c;
|
||||
}
|
||||
void const* getExternal() const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::VoidPtr);
|
||||
return _value.e;
|
||||
}
|
||||
|
||||
};
|
||||
char const* getCharPtr() const {
|
||||
VELOCYPACK_ASSERT(_cType == CType::CharPtr);
|
||||
return _value.c;
|
||||
}
|
||||
};
|
||||
|
||||
class ValuePair {
|
||||
uint8_t const* _start;
|
||||
uint64_t _size;
|
||||
ValueType _type;
|
||||
class ValuePair {
|
||||
uint8_t const* _start;
|
||||
uint64_t _size;
|
||||
ValueType _type;
|
||||
|
||||
public:
|
||||
public:
|
||||
ValuePair(uint8_t const* start, uint64_t size,
|
||||
ValueType type = ValueType::Binary)
|
||||
: _start(start), _size(size), _type(type) {}
|
||||
|
||||
ValuePair (uint8_t const* start, uint64_t size,
|
||||
ValueType type = ValueType::Binary)
|
||||
: _start(start), _size(size), _type(type) {
|
||||
}
|
||||
ValuePair(char const* start, uint64_t size,
|
||||
ValueType type = ValueType::Binary)
|
||||
: _start(reinterpret_cast<uint8_t const*>(start)),
|
||||
_size(size),
|
||||
_type(type) {}
|
||||
|
||||
ValuePair (char const* start, uint64_t size,
|
||||
ValueType type = ValueType::Binary)
|
||||
: _start(reinterpret_cast<uint8_t const*>(start)),
|
||||
_size(size), _type(type) {
|
||||
}
|
||||
explicit ValuePair(uint64_t size, ValueType type = ValueType::Binary)
|
||||
: _start(nullptr), _size(size), _type(type) {}
|
||||
|
||||
explicit ValuePair (uint64_t size,
|
||||
ValueType type = ValueType::Binary)
|
||||
: _start(nullptr), _size(size), _type(type) {
|
||||
}
|
||||
uint8_t const* getStart() const { return _start; }
|
||||
|
||||
uint8_t const* getStart () const {
|
||||
return _start;
|
||||
}
|
||||
uint64_t getSize() const { return _size; }
|
||||
|
||||
uint64_t getSize () const {
|
||||
return _size;
|
||||
}
|
||||
ValueType valueType() const { return _type; }
|
||||
|
||||
ValueType valueType () const {
|
||||
return _type;
|
||||
}
|
||||
bool isString() const { return _type == ValueType::String; }
|
||||
};
|
||||
|
||||
bool isString () const {
|
||||
return _type == ValueType::String;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,33 +32,33 @@
|
|||
#include "velocypack-common.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
namespace velocypack {
|
||||
|
||||
enum class ValueType {
|
||||
None, // not yet initialized
|
||||
Null, // JSON null
|
||||
Bool,
|
||||
Array,
|
||||
Object,
|
||||
Double,
|
||||
UTCDate,
|
||||
External,
|
||||
MinKey,
|
||||
MaxKey,
|
||||
Int,
|
||||
UInt,
|
||||
SmallInt,
|
||||
String,
|
||||
Binary,
|
||||
BCD,
|
||||
Custom
|
||||
};
|
||||
enum class ValueType {
|
||||
None, // not yet initialized
|
||||
Null, // JSON null
|
||||
Bool,
|
||||
Array,
|
||||
Object,
|
||||
Double,
|
||||
UTCDate,
|
||||
External,
|
||||
MinKey,
|
||||
MaxKey,
|
||||
Int,
|
||||
UInt,
|
||||
SmallInt,
|
||||
String,
|
||||
Binary,
|
||||
BCD,
|
||||
Custom
|
||||
};
|
||||
|
||||
char const* valueTypeName (ValueType);
|
||||
char const* valueTypeName(ValueType);
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
std::ostream& operator<< (std::ostream&, arangodb::velocypack::ValueType);
|
||||
std::ostream& operator<<(std::ostream&, arangodb::velocypack::ValueType);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,31 +32,32 @@
|
|||
#include "velocypack/velocypack-common.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
namespace velocypack {
|
||||
|
||||
struct Version {
|
||||
Version () = delete;
|
||||
Version (Version const&) = delete;
|
||||
Version& operator = (Version const&) = delete;
|
||||
struct Version {
|
||||
Version() = delete;
|
||||
Version(Version const&) = delete;
|
||||
Version& operator=(Version const&) = delete;
|
||||
|
||||
Version (int majorValue, int minorValue, int patchValue)
|
||||
: majorValue(majorValue), minorValue(minorValue), patchValue(patchValue) {
|
||||
}
|
||||
Version(int majorValue, int minorValue, int patchValue)
|
||||
: majorValue(majorValue),
|
||||
minorValue(minorValue),
|
||||
patchValue(patchValue) {}
|
||||
|
||||
std::string toString () const;
|
||||
std::string toString() const;
|
||||
|
||||
int compare (Version const& other) const;
|
||||
int compare(Version const& other) const;
|
||||
|
||||
static int compare (Version const& lhs, Version const& rhs);
|
||||
static int compare(Version const& lhs, Version const& rhs);
|
||||
|
||||
int const majorValue;
|
||||
int const minorValue;
|
||||
int const patchValue;
|
||||
int const majorValue;
|
||||
int const minorValue;
|
||||
int const patchValue;
|
||||
|
||||
static Version const BuildVersion;
|
||||
};
|
||||
static Version const BuildVersion;
|
||||
};
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,124 +29,125 @@
|
|||
// this header can be included multiple times
|
||||
|
||||
namespace {
|
||||
// unconditional typedefs
|
||||
// unconditional typedefs
|
||||
#ifndef VELOCYPACK_ALIAS_VPACKVALUELENGTH
|
||||
#define VELOCYPACK_ALIAS_VPACKVALUELENGTH
|
||||
using VPackValueLength = arangodb::velocypack::ValueLength;
|
||||
using VPackValueLength = arangodb::velocypack::ValueLength;
|
||||
#endif
|
||||
|
||||
// conditional typedefs, only used when the respective headers are already included
|
||||
|
||||
// conditional typedefs, only used when the respective headers are already
|
||||
// included
|
||||
|
||||
#ifdef VELOCYPACK_ITERATOR_H
|
||||
#ifndef VELOCYPACK_ALIAS_ITERATOR
|
||||
#define VELOCYPACK_ALIAS_ITERATOR
|
||||
using VPackArrayIterator = arangodb::velocypack::ArrayIterator;
|
||||
using VPackObjectIterator = arangodb::velocypack::ObjectIterator;
|
||||
using VPackArrayIterator = arangodb::velocypack::ArrayIterator;
|
||||
using VPackObjectIterator = arangodb::velocypack::ObjectIterator;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_BUILDER_H
|
||||
#ifndef VELOCYPACK_ALIAS_BUILDER
|
||||
#define VELOCYPACK_ALIAS_BUILDER
|
||||
using VPackBuilder = arangodb::velocypack::Builder;
|
||||
using VPackBuilder = arangodb::velocypack::Builder;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_BUFFER_H
|
||||
#ifndef VELOCYPACK_ALIAS_BUFFER
|
||||
#define VELOCYPACK_ALIAS_BUFFER
|
||||
using VPackCharBuffer = arangodb::velocypack::CharBuffer;
|
||||
using VPackCharBuffer = arangodb::velocypack::CharBuffer;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_SINK_H
|
||||
#ifndef VELOCYPACK_ALIAS_SINK
|
||||
#define VELOCYPACK_ALIAS_SINK
|
||||
using VPackSink = arangodb::velocypack::Sink;
|
||||
using VPackCharBufferSink = arangodb::velocypack::CharBufferSink;
|
||||
using VPackStringSink = arangodb::velocypack::StringSink;
|
||||
using VPackStringStreamSink = arangodb::velocypack::StringStreamSink;
|
||||
using VPackSink = arangodb::velocypack::Sink;
|
||||
using VPackCharBufferSink = arangodb::velocypack::CharBufferSink;
|
||||
using VPackStringSink = arangodb::velocypack::StringSink;
|
||||
using VPackStringStreamSink = arangodb::velocypack::StringStreamSink;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_COLLECTION_H
|
||||
#ifndef VELOCYPACK_ALIAS_COLLECTION
|
||||
#define VELOCYPACK_ALIAS_COLLECTION
|
||||
using VPackCollection = arangodb::velocypack::Collection;
|
||||
using VPackCollection = arangodb::velocypack::Collection;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_ATTRIBUTETRANSLATOR_H
|
||||
#ifndef VELOCYPACK_ALIAS_ATTRIBUTETRANSLATOR
|
||||
#define VELOCYPACK_ALIAS_ATTRIBUTETRANSLATOR
|
||||
using VPackAttributeTranslator = arangodb::velocypack::AttributeTranslator;
|
||||
using VPackAttributeTranslator = arangodb::velocypack::AttributeTranslator;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_DUMPER_H
|
||||
#ifndef VELOCYPACK_ALIAS_DUMPER
|
||||
#define VELOCYPACK_ALIAS_DUMPER
|
||||
using VPackDumper = arangodb::velocypack::Dumper;
|
||||
using VPackDumper = arangodb::velocypack::Dumper;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_EXCEPTION_H
|
||||
#ifndef VELOCYPACK_ALIAS_EXCEPTION
|
||||
#define VELOCYPACK_ALIAS_EXCEPTION
|
||||
using VPackException = arangodb::velocypack::Exception;
|
||||
using VPackException = arangodb::velocypack::Exception;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_HEXDUMP_H
|
||||
#ifndef VELOCYPACK_ALIAS_HEXDUMP
|
||||
#define VELOCYPACK_ALIAS_HEXDUMP
|
||||
using VPackHexDump = arangodb::velocypack::HexDump;
|
||||
using VPackHexDump = arangodb::velocypack::HexDump;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_OPTIONS_H
|
||||
#ifndef VELOCYPACK_ALIAS_OPTIONS
|
||||
#define VELOCYPACK_ALIAS_OPTIONS
|
||||
using VPackOptions = arangodb::velocypack::Options;
|
||||
using VPackAttributeExcludeHandler = arangodb::velocypack::AttributeExcludeHandler;
|
||||
using VPackCustomTypeHandler = arangodb::velocypack::CustomTypeHandler;
|
||||
using VPackOptions = arangodb::velocypack::Options;
|
||||
using VPackAttributeExcludeHandler =
|
||||
arangodb::velocypack::AttributeExcludeHandler;
|
||||
using VPackCustomTypeHandler = arangodb::velocypack::CustomTypeHandler;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_PARSER_H
|
||||
#ifndef VELOCYPACK_ALIAS_PARSER
|
||||
#define VELOCYPACK_ALIAS_PARSER
|
||||
using VPackParser = arangodb::velocypack::Parser;
|
||||
using VPackParser = arangodb::velocypack::Parser;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_SLICE_H
|
||||
#ifndef VELOCYPACK_ALIAS_SLICE
|
||||
#define VELOCYPACK_ALIAS_SLICE
|
||||
using VPackSlice = arangodb::velocypack::Slice;
|
||||
using VPackSlice = arangodb::velocypack::Slice;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_VALUE_H
|
||||
#ifndef VELOCYPACK_ALIAS_VALUE
|
||||
#define VELOCYPACK_ALIAS_VALUE
|
||||
using VPackValue = arangodb::velocypack::Value;
|
||||
using VPackValuePair = arangodb::velocypack::ValuePair;
|
||||
using VPackValue = arangodb::velocypack::Value;
|
||||
using VPackValuePair = arangodb::velocypack::ValuePair;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_VALUETYPE_H
|
||||
#ifndef VELOCYPACK_ALIAS_VALUETYPE
|
||||
#define VELOCYPACK_ALIAS_VALUETYPE
|
||||
using VPackValueType = arangodb::velocypack::ValueType;
|
||||
using VPackValueType = arangodb::velocypack::ValueType;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef VELOCYPACK_VERSION_H
|
||||
#ifndef VELOCYPACK_ALIAS_VERSION
|
||||
#define VELOCYPACK_ALIAS_VERSION
|
||||
using VPackVersion = arangodb::velocypack::Version;
|
||||
using VPackVersion = arangodb::velocypack::Version;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
#ifndef NDEBUG
|
||||
#define NDEBUG
|
||||
#endif
|
||||
#define VELOCYPACK_ASSERT(x)
|
||||
#define VELOCYPACK_ASSERT(x)
|
||||
#endif
|
||||
|
||||
// check for environment type (32 or 64 bit)
|
||||
|
@ -61,130 +61,125 @@
|
|||
|
||||
// attribute used to tag potentially unused functions (used mostly in tests/)
|
||||
#ifdef __GNUC__
|
||||
#define VELOCYPACK_UNUSED __attribute__ ((unused))
|
||||
#define VELOCYPACK_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define VELOCYPACK_UNUSED /* unused */
|
||||
#endif
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
namespace velocypack {
|
||||
|
||||
// unified size type for VPack, can be used on 32 and 64 bit
|
||||
// though no VPack values can exceed the bounds of 32 bit on a 32 bit OS
|
||||
typedef uint64_t ValueLength;
|
||||
// unified size type for VPack, can be used on 32 and 64 bit
|
||||
// though no VPack values can exceed the bounds of 32 bit on a 32 bit OS
|
||||
typedef uint64_t ValueLength;
|
||||
|
||||
#ifndef VELOCYPACK_64BIT
|
||||
// check if the length is beyond the size of a SIZE_MAX on this platform
|
||||
static void checkValueLength (ValueLength);
|
||||
// check if the length is beyond the size of a SIZE_MAX on this platform
|
||||
static void checkValueLength(ValueLength);
|
||||
#else
|
||||
static inline void checkValueLength (ValueLength) {
|
||||
// do nothing on a 64 bit platform
|
||||
}
|
||||
static inline void checkValueLength(ValueLength) {
|
||||
// do nothing on a 64 bit platform
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
// 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);
|
||||
// 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);
|
||||
}
|
||||
if (reverse) {
|
||||
while (value >= 0x80) {
|
||||
*dst-- = static_cast<uint8_t>(value | 0x80);
|
||||
value >>= 7;
|
||||
}
|
||||
|
||||
// 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;
|
||||
int64_t shift = static_cast<int64_t>(shift2 - 1);
|
||||
return v >= 0 ? static_cast<uint64_t>(v)
|
||||
: static_cast<uint64_t>((v + shift) + 1) + shift2;
|
||||
// Note that g++ and clang++ with -O3 compile this away to
|
||||
// nothing. Further note that a plain cast from int64_t to
|
||||
// uint64_t is not guaranteed to work for negative values!
|
||||
*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);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
: static_cast<int64_t>(v);
|
||||
}
|
||||
// returns current value for UTCDate
|
||||
int64_t currentUTCDateValue();
|
||||
|
||||
// read an unsigned little endian integer value of the
|
||||
// specified length, starting at the specified byte offset
|
||||
template<typename T>
|
||||
static inline T readInteger (uint8_t const* start, ValueLength length) throw() {
|
||||
uint64_t value = 0;
|
||||
uint64_t x = 0;
|
||||
uint8_t const* end = start + length;
|
||||
do {
|
||||
value += static_cast<T>(*start++) << x;
|
||||
x += 8;
|
||||
}
|
||||
while (start < end);
|
||||
return value;
|
||||
}
|
||||
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;
|
||||
int64_t shift = static_cast<int64_t>(shift2 - 1);
|
||||
return v >= 0 ? static_cast<uint64_t>(v)
|
||||
: static_cast<uint64_t>((v + shift) + 1) + shift2;
|
||||
// Note that g++ and clang++ with -O3 compile this away to
|
||||
// nothing. Further note that a plain cast from int64_t to
|
||||
// uint64_t is not guaranteed to work for negative values!
|
||||
}
|
||||
|
||||
static inline uint64_t readUInt64 (uint8_t const* start) throw() {
|
||||
return readInteger<uint64_t>(start, 8);
|
||||
}
|
||||
|
||||
static inline void storeUInt64 (uint8_t* start, uint64_t value) throw() {
|
||||
uint8_t const* end = start + 8;
|
||||
do {
|
||||
*start++ = static_cast<uint8_t>(value & 0xff);
|
||||
value >>= 8;
|
||||
}
|
||||
while (start < end);
|
||||
}
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
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
|
||||
: static_cast<int64_t>(v);
|
||||
}
|
||||
|
||||
// read an unsigned little endian integer value of the
|
||||
// specified length, starting at the specified byte offset
|
||||
template <typename T>
|
||||
static inline T readInteger(uint8_t const* start, ValueLength length) throw() {
|
||||
uint64_t value = 0;
|
||||
uint64_t x = 0;
|
||||
uint8_t const* end = start + length;
|
||||
do {
|
||||
value += static_cast<T>(*start++) << x;
|
||||
x += 8;
|
||||
} while (start < end);
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline uint64_t readUInt64(uint8_t const* start) throw() {
|
||||
return readInteger<uint64_t>(start, 8);
|
||||
}
|
||||
|
||||
static inline void storeUInt64(uint8_t* start, uint64_t value) throw() {
|
||||
uint8_t const* end = start + 8;
|
||||
do {
|
||||
*start++ = static_cast<uint8_t>(value & 0xff);
|
||||
value >>= 8;
|
||||
} while (start < end);
|
||||
}
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
#include "velocypack/Value.h"
|
||||
|
||||
using namespace arangodb::velocypack;
|
||||
|
||||
void AttributeTranslator::add (std::string const& key, uint64_t id) {
|
||||
|
||||
void AttributeTranslator::add(std::string const& key, uint64_t id) {
|
||||
if (_builder == nullptr) {
|
||||
_builder.reset(new Builder);
|
||||
_builder->add(Value(ValueType::Object));
|
||||
|
@ -43,7 +43,7 @@ void AttributeTranslator::add (std::string const& key, uint64_t id) {
|
|||
_count++;
|
||||
}
|
||||
|
||||
void AttributeTranslator::seal () {
|
||||
void AttributeTranslator::seal() {
|
||||
if (_builder == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ void AttributeTranslator::seal () {
|
|||
}
|
||||
|
||||
// translate from string to id
|
||||
uint8_t const* AttributeTranslator::translate (std::string const& key) const {
|
||||
uint8_t const* AttributeTranslator::translate(std::string const& key) const {
|
||||
auto it = _keyToId.find(key);
|
||||
|
||||
if (it == _keyToId.end()) {
|
||||
|
@ -73,7 +73,8 @@ uint8_t const* AttributeTranslator::translate (std::string const& key) const {
|
|||
}
|
||||
|
||||
// translate from string to id
|
||||
uint8_t const* AttributeTranslator::translate (char const* key, ValueLength length) const {
|
||||
uint8_t const* AttributeTranslator::translate(char const* key,
|
||||
ValueLength length) const {
|
||||
auto it = _keyToId.find(std::string(key, length));
|
||||
|
||||
if (it == _keyToId.end()) {
|
||||
|
@ -84,7 +85,7 @@ uint8_t const* AttributeTranslator::translate (char const* key, ValueLength leng
|
|||
}
|
||||
|
||||
// translate from id to string
|
||||
uint8_t const* AttributeTranslator::translate (uint64_t id) const {
|
||||
uint8_t const* AttributeTranslator::translate(uint64_t id) const {
|
||||
auto it = _idToKey.find(id);
|
||||
|
||||
if (it == _idToKey.end()) {
|
||||
|
@ -93,4 +94,3 @@ uint8_t const* AttributeTranslator::translate (uint64_t id) const {
|
|||
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,32 +32,31 @@
|
|||
#include "velocypack/Sink.h"
|
||||
|
||||
using namespace arangodb::velocypack;
|
||||
|
||||
std::string Builder::toString () const {
|
||||
|
||||
std::string Builder::toString() const {
|
||||
std::string buffer;
|
||||
StringSink sink(&buffer);
|
||||
Dumper::dump(slice(), &sink, options);
|
||||
return std::move(buffer);
|
||||
}
|
||||
|
||||
void Builder::doActualSort (std::vector<SortEntry>& entries) {
|
||||
void Builder::doActualSort(std::vector<SortEntry>& entries) {
|
||||
VELOCYPACK_ASSERT(entries.size() > 1);
|
||||
std::sort(entries.begin(), entries.end(),
|
||||
[] (SortEntry const& a, SortEntry const& b) {
|
||||
// return true iff a < b:
|
||||
uint8_t const* pa = a.nameStart;
|
||||
uint64_t sizea = a.nameSize;
|
||||
uint8_t const* pb = b.nameStart;
|
||||
uint64_t sizeb = b.nameSize;
|
||||
size_t const compareLength
|
||||
= static_cast<size_t>((std::min)(sizea, sizeb));
|
||||
int res = memcmp(pa, pb, compareLength);
|
||||
std::sort(entries.begin(), entries.end(),
|
||||
[](SortEntry const& a, SortEntry const& b) {
|
||||
// return true iff a < b:
|
||||
uint8_t const* pa = a.nameStart;
|
||||
uint64_t sizea = a.nameSize;
|
||||
uint8_t const* pb = b.nameStart;
|
||||
uint64_t sizeb = b.nameSize;
|
||||
size_t const compareLength = static_cast<size_t>((std::min)(sizea, sizeb));
|
||||
int res = memcmp(pa, pb, compareLength);
|
||||
|
||||
return (res < 0 || (res == 0 && sizea < sizeb));
|
||||
});
|
||||
return (res < 0 || (res == 0 && sizea < sizeb));
|
||||
});
|
||||
};
|
||||
|
||||
uint8_t const* Builder::findAttrName (uint8_t const* base, uint64_t& len) {
|
||||
uint8_t const* Builder::findAttrName(uint8_t const* base, uint64_t& len) {
|
||||
uint8_t const b = *base;
|
||||
if (b >= 0x40 && b <= 0xbe) {
|
||||
// short UTF-8 string
|
||||
|
@ -71,24 +70,22 @@ uint8_t const* Builder::findAttrName (uint8_t const* base, uint64_t& len) {
|
|||
for (size_t i = 8; i >= 1; i--) {
|
||||
len = (len << 8) + base[i];
|
||||
}
|
||||
return base + 1 + 8; // string starts here
|
||||
return base + 1 + 8; // string starts here
|
||||
}
|
||||
throw Exception(Exception::NotImplemented, "Invalid Object key type");
|
||||
}
|
||||
|
||||
void Builder::sortObjectIndexShort (uint8_t* objBase,
|
||||
std::vector<ValueLength>& offsets) {
|
||||
auto cmp = [&] (ValueLength a, ValueLength b) -> bool {
|
||||
void Builder::sortObjectIndexShort(uint8_t* objBase,
|
||||
std::vector<ValueLength>& offsets) {
|
||||
auto cmp = [&](ValueLength a, ValueLength b) -> bool {
|
||||
uint8_t const* aa = objBase + a;
|
||||
uint8_t const* bb = objBase + b;
|
||||
if (*aa >= 0x40 && *aa <= 0xbe &&
|
||||
*bb >= 0x40 && *bb <= 0xbe) {
|
||||
if (*aa >= 0x40 && *aa <= 0xbe && *bb >= 0x40 && *bb <= 0xbe) {
|
||||
// The fast path, short strings:
|
||||
uint8_t m = (std::min)(*aa - 0x40, *bb - 0x40);
|
||||
int c = memcmp(aa+1, bb+1, static_cast<size_t>(m));
|
||||
int c = memcmp(aa + 1, bb + 1, static_cast<size_t>(m));
|
||||
return (c < 0 || (c == 0 && *aa < *bb));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
uint64_t lena;
|
||||
uint64_t lenb;
|
||||
aa = findAttrName(aa, lena);
|
||||
|
@ -101,10 +98,9 @@ void Builder::sortObjectIndexShort (uint8_t* objBase,
|
|||
std::sort(offsets.begin(), offsets.end(), cmp);
|
||||
}
|
||||
|
||||
void Builder::sortObjectIndexLong (uint8_t* objBase,
|
||||
std::vector<ValueLength>& offsets) {
|
||||
|
||||
// on some platforms we can use a thread-local vector
|
||||
void Builder::sortObjectIndexLong(uint8_t* objBase,
|
||||
std::vector<ValueLength>& offsets) {
|
||||
// on some platforms we can use a thread-local vector
|
||||
#if __llvm__ == 1
|
||||
// nono thread local
|
||||
std::vector<Builder::SortEntry> entries;
|
||||
|
@ -115,7 +111,7 @@ void Builder::sortObjectIndexLong (uint8_t* objBase,
|
|||
thread_local std::vector<Builder::SortEntry> entries;
|
||||
entries.clear();
|
||||
#endif
|
||||
|
||||
|
||||
entries.reserve(offsets.size());
|
||||
for (ValueLength i = 0; i < offsets.size(); i++) {
|
||||
SortEntry e;
|
||||
|
@ -126,23 +122,22 @@ void Builder::sortObjectIndexLong (uint8_t* objBase,
|
|||
VELOCYPACK_ASSERT(entries.size() == offsets.size());
|
||||
doActualSort(entries);
|
||||
|
||||
// copy back the sorted offsets
|
||||
// copy back the sorted offsets
|
||||
for (ValueLength i = 0; i < offsets.size(); i++) {
|
||||
offsets[i] = entries[i].offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::sortObjectIndex (uint8_t* objBase,
|
||||
std::vector<ValueLength>& offsets) {
|
||||
void Builder::sortObjectIndex(uint8_t* objBase,
|
||||
std::vector<ValueLength>& offsets) {
|
||||
if (offsets.size() > 32) {
|
||||
sortObjectIndexLong(objBase, offsets);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sortObjectIndexShort(objBase, offsets);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::removeLast () {
|
||||
void Builder::removeLast() {
|
||||
if (_stack.empty()) {
|
||||
throw Exception(Exception::BuilderNeedOpenCompound);
|
||||
}
|
||||
|
@ -155,7 +150,7 @@ void Builder::removeLast () {
|
|||
index.pop_back();
|
||||
}
|
||||
|
||||
void Builder::close () {
|
||||
void Builder::close() {
|
||||
if (isClosed()) {
|
||||
throw Exception(Exception::BuilderNeedOpenCompound);
|
||||
}
|
||||
|
@ -182,30 +177,30 @@ void Builder::close () {
|
|||
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))) {
|
||||
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()));
|
||||
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;
|
||||
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
|
||||
// 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));
|
||||
memmove(_start + tos + targetPos, _start + tos + 9, _pos - (tos + 9));
|
||||
}
|
||||
|
||||
// store byte length
|
||||
|
@ -216,8 +211,9 @@ void Builder::close () {
|
|||
if (nLen > 8 - bLen) {
|
||||
reserveSpace(nLen);
|
||||
}
|
||||
storeVariableValueLength<true>(_start + tos + byteSize - 1, static_cast<ValueLength>(index.size()));
|
||||
|
||||
storeVariableValueLength<true>(_start + tos + byteSize - 1,
|
||||
static_cast<ValueLength>(index.size()));
|
||||
|
||||
_pos -= 8;
|
||||
_pos += nLen + bLen;
|
||||
|
||||
|
@ -225,9 +221,9 @@ void Builder::close () {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// fix head byte in case a compact Array / Object was originally requested
|
||||
_start[tos] = (isArray ? 0x06 : 0x0b);
|
||||
_start[tos] = (isArray ? 0x06 : 0x0b);
|
||||
|
||||
bool needIndexTable = true;
|
||||
bool needNrSubs = true;
|
||||
|
@ -237,17 +233,15 @@ void Builder::close () {
|
|||
needNrSubs = false;
|
||||
}
|
||||
// For objects we leave needNrSubs at true here!
|
||||
}
|
||||
else if (_start[tos] == 0x06 && // an Array
|
||||
(_pos - tos) - index[0] == index.size() * (index[1] - index[0])) {
|
||||
} 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:
|
||||
bool noTable = true;
|
||||
ValueLength const subLen = index[1] - index[0];
|
||||
if ((_pos - tos) - index[index.size() - 1] != subLen) {
|
||||
noTable = false;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
for (size_t i = 1; i < index.size() - 1; i++) {
|
||||
if (index[i + 1] - index[i] != subLen) {
|
||||
noTable = false;
|
||||
|
@ -262,36 +256,33 @@ void Builder::close () {
|
|||
}
|
||||
|
||||
// First determine byte length and its format:
|
||||
unsigned int offsetSize;
|
||||
// can be 1, 2, 4 or 8 for the byte width of the offsets,
|
||||
// the byte length and the number of subvalues:
|
||||
if (_pos - tos + (needIndexTable ? index.size() : 0)
|
||||
- (needNrSubs ? 6 : 7) <= 0xff) {
|
||||
unsigned int offsetSize;
|
||||
// can be 1, 2, 4 or 8 for the byte width of the offsets,
|
||||
// the byte length and the number of subvalues:
|
||||
if (_pos - tos + (needIndexTable ? index.size() : 0) - (needNrSubs ? 6 : 7) <=
|
||||
0xff) {
|
||||
// We have so far used _pos - tos bytes, including the reserved 8
|
||||
// bytes for byte length and number of subvalues. In the 1-byte number
|
||||
// case we would win back 6 bytes but would need one byte per subvalue
|
||||
// for the index table
|
||||
offsetSize = 1;
|
||||
}
|
||||
else if (_pos - tos + (needIndexTable ? 2 * index.size() : 0) <= 0xffff) {
|
||||
} else if (_pos - tos + (needIndexTable ? 2 * index.size() : 0) <= 0xffff) {
|
||||
offsetSize = 2;
|
||||
}
|
||||
else if (_pos - tos + (needIndexTable ? 4 * index.size() : 0) <= 0xffffffffu) {
|
||||
} else if (_pos - tos + (needIndexTable ? 4 * index.size() : 0) <=
|
||||
0xffffffffu) {
|
||||
offsetSize = 4;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
offsetSize = 8;
|
||||
}
|
||||
|
||||
// Maybe we need to move down data:
|
||||
if (offsetSize == 1) {
|
||||
unsigned int targetPos = 3;
|
||||
if (! needIndexTable && _start[tos] == 0x06) {
|
||||
if (!needIndexTable && _start[tos] == 0x06) {
|
||||
targetPos = 2;
|
||||
}
|
||||
if (_pos > (tos + 9)) {
|
||||
memmove(_start + tos + targetPos, _start + tos + 9,
|
||||
_pos - (tos + 9));
|
||||
memmove(_start + tos + targetPos, _start + tos + 9, _pos - (tos + 9));
|
||||
}
|
||||
_pos -= (9 - targetPos);
|
||||
for (size_t i = 0; i < index.size(); i++) {
|
||||
|
@ -308,13 +299,11 @@ void Builder::close () {
|
|||
reserveSpace(offsetSize * index.size() + (offsetSize == 8 ? 8 : 0));
|
||||
tableBase = _pos;
|
||||
_pos += offsetSize * index.size();
|
||||
if (_start[tos] == 0x0b) {
|
||||
if (_start[tos] == 0x0b) {
|
||||
// Object
|
||||
if (! options->sortAttributeNames) {
|
||||
if (!options->sortAttributeNames) {
|
||||
_start[tos] = 0x0f; // unsorted
|
||||
}
|
||||
else if (index.size() >= 2 &&
|
||||
options->sortAttributeNames) {
|
||||
} else if (index.size() >= 2 && options->sortAttributeNames) {
|
||||
sortObjectIndex(_start + tos, index);
|
||||
}
|
||||
}
|
||||
|
@ -325,8 +314,7 @@ void Builder::close () {
|
|||
x >>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // no index table
|
||||
} else { // no index table
|
||||
if (_start[tos] == 0x06) {
|
||||
_start[tos] = 0x02;
|
||||
}
|
||||
|
@ -335,11 +323,9 @@ void Builder::close () {
|
|||
if (offsetSize > 1) {
|
||||
if (offsetSize == 2) {
|
||||
_start[tos] += 1;
|
||||
}
|
||||
else if (offsetSize == 4) {
|
||||
} else if (offsetSize == 4) {
|
||||
_start[tos] += 2;
|
||||
}
|
||||
else { // offsetSize == 8
|
||||
} else { // offsetSize == 8
|
||||
_start[tos] += 3;
|
||||
if (needNrSubs) {
|
||||
appendLength(index.size(), 8);
|
||||
|
@ -369,14 +355,14 @@ void Builder::close () {
|
|||
checkAttributeUniqueness(Slice(_start + tos, options));
|
||||
}
|
||||
|
||||
// Now the array or object is complete, we pop a ValueLength
|
||||
// Now the array or object is complete, we pop a ValueLength
|
||||
// off the _stack:
|
||||
_stack.pop_back();
|
||||
// Intentionally leave _index[depth] intact to avoid future allocs!
|
||||
}
|
||||
|
||||
// checks whether an Object value has a specific key attribute
|
||||
bool Builder::hasKey (std::string const& key) const {
|
||||
bool Builder::hasKey(std::string const& key) const {
|
||||
if (_stack.empty()) {
|
||||
throw Exception(Exception::BuilderNeedOpenObject);
|
||||
}
|
||||
|
@ -394,11 +380,11 @@ bool Builder::hasKey (std::string const& key) const {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// return an attribute from an Object value
|
||||
Slice Builder::getKey (std::string const& key) const {
|
||||
// return the value for a specific key of an Object value
|
||||
Slice Builder::getKey(std::string const& key) const {
|
||||
if (_stack.empty()) {
|
||||
throw Exception(Exception::BuilderNeedOpenObject);
|
||||
}
|
||||
|
@ -412,14 +398,17 @@ Slice Builder::getKey (std::string const& key) const {
|
|||
}
|
||||
for (size_t i = 0; i < index.size(); ++i) {
|
||||
Slice s(_start + tos + index[i], options);
|
||||
if (!s.isString()) {
|
||||
s = s.makeKey();
|
||||
}
|
||||
if (s.isString() && s.isEqualString(key)) {
|
||||
return s;
|
||||
return Slice(s.start() + s.byteSize(), options);
|
||||
}
|
||||
}
|
||||
return Slice();
|
||||
return Slice();
|
||||
}
|
||||
|
||||
uint8_t* Builder::set (Value const& item) {
|
||||
uint8_t* Builder::set(Value const& item) {
|
||||
auto const oldPos = _start + _pos;
|
||||
auto ctype = item.cType();
|
||||
|
||||
|
@ -428,7 +417,8 @@ uint8_t* Builder::set (Value const& item) {
|
|||
// table is created and a new ValueLength is pushed onto the stack.
|
||||
switch (item.valueType()) {
|
||||
case ValueType::None: {
|
||||
throw Exception(Exception::BuilderUnexpectedType, "Cannot set a ValueType::None");
|
||||
throw Exception(Exception::BuilderUnexpectedType,
|
||||
"Cannot set a ValueType::None");
|
||||
}
|
||||
case ValueType::Null: {
|
||||
reserveSpace(1);
|
||||
|
@ -437,13 +427,13 @@ uint8_t* Builder::set (Value const& item) {
|
|||
}
|
||||
case ValueType::Bool: {
|
||||
if (ctype != Value::CType::Bool) {
|
||||
throw Exception(Exception::BuilderUnexpectedValue, "Must give bool for ValueType::Bool");
|
||||
throw Exception(Exception::BuilderUnexpectedValue,
|
||||
"Must give bool for ValueType::Bool");
|
||||
}
|
||||
reserveSpace(1);
|
||||
if (item.getBool()) {
|
||||
_start[_pos++] = 0x1a;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
_start[_pos++] = 0x19;
|
||||
}
|
||||
break;
|
||||
|
@ -464,7 +454,8 @@ uint8_t* Builder::set (Value const& item) {
|
|||
v = static_cast<double>(item.getUInt64());
|
||||
break;
|
||||
default:
|
||||
throw Exception(Exception::BuilderUnexpectedValue, "Must give number for ValueType::Double");
|
||||
throw Exception(Exception::BuilderUnexpectedValue,
|
||||
"Must give number for ValueType::Double");
|
||||
}
|
||||
reserveSpace(1 + sizeof(double));
|
||||
_start[_pos++] = 0x1b;
|
||||
|
@ -473,8 +464,14 @@ uint8_t* Builder::set (Value const& item) {
|
|||
break;
|
||||
}
|
||||
case ValueType::External: {
|
||||
if (options->disallowExternals) {
|
||||
// External values explicitly disallowed as a security
|
||||
// precaution
|
||||
throw Exception(Exception::BuilderExternalsDisallowed);
|
||||
}
|
||||
if (ctype != Value::CType::VoidPtr) {
|
||||
throw Exception(Exception::BuilderUnexpectedValue, "Must give void pointer for ValueType::External");
|
||||
throw Exception(Exception::BuilderUnexpectedValue,
|
||||
"Must give void pointer for ValueType::External");
|
||||
}
|
||||
reserveSpace(1 + sizeof(void*));
|
||||
// store pointer. this doesn't need to be portable
|
||||
|
@ -497,16 +494,17 @@ uint8_t* Builder::set (Value const& item) {
|
|||
vv = static_cast<int64_t>(item.getUInt64());
|
||||
break;
|
||||
default:
|
||||
throw Exception(Exception::BuilderUnexpectedValue, "Must give number for ValueType::SmallInt");
|
||||
throw Exception(Exception::BuilderUnexpectedValue,
|
||||
"Must give number for ValueType::SmallInt");
|
||||
}
|
||||
if (vv < -6 || vv > 9) {
|
||||
throw Exception(Exception::NumberOutOfRange, "Number out of range of ValueType::SmallInt");
|
||||
}
|
||||
throw Exception(Exception::NumberOutOfRange,
|
||||
"Number out of range of ValueType::SmallInt");
|
||||
}
|
||||
reserveSpace(1);
|
||||
if (vv >= 0) {
|
||||
_start[_pos++] = static_cast<uint8_t>(vv + 0x30);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
_start[_pos++] = static_cast<uint8_t>(vv + 0x40);
|
||||
}
|
||||
break;
|
||||
|
@ -524,7 +522,8 @@ uint8_t* Builder::set (Value const& item) {
|
|||
v = toInt64(item.getUInt64());
|
||||
break;
|
||||
default:
|
||||
throw Exception(Exception::BuilderUnexpectedValue, "Must give number for ValueType::Int");
|
||||
throw Exception(Exception::BuilderUnexpectedValue,
|
||||
"Must give number for ValueType::Int");
|
||||
}
|
||||
addInt(v);
|
||||
break;
|
||||
|
@ -534,13 +533,17 @@ uint8_t* Builder::set (Value const& item) {
|
|||
switch (ctype) {
|
||||
case Value::CType::Double:
|
||||
if (item.getDouble() < 0.0) {
|
||||
throw Exception(Exception::BuilderUnexpectedValue, "Must give non-negative number for ValueType::UInt");
|
||||
throw Exception(
|
||||
Exception::BuilderUnexpectedValue,
|
||||
"Must give non-negative number for ValueType::UInt");
|
||||
}
|
||||
v = static_cast<uint64_t>(item.getDouble());
|
||||
break;
|
||||
case Value::CType::Int64:
|
||||
if (item.getInt64() < 0) {
|
||||
throw Exception(Exception::BuilderUnexpectedValue, "Must give non-negative number for ValueType::UInt");
|
||||
throw Exception(
|
||||
Exception::BuilderUnexpectedValue,
|
||||
"Must give non-negative number for ValueType::UInt");
|
||||
}
|
||||
v = static_cast<uint64_t>(item.getInt64());
|
||||
break;
|
||||
|
@ -548,9 +551,10 @@ uint8_t* Builder::set (Value const& item) {
|
|||
v = item.getUInt64();
|
||||
break;
|
||||
default:
|
||||
throw Exception(Exception::BuilderUnexpectedValue, "Must give number for ValueType::UInt");
|
||||
throw Exception(Exception::BuilderUnexpectedValue,
|
||||
"Must give number for ValueType::UInt");
|
||||
}
|
||||
addUInt(v);
|
||||
addUInt(v);
|
||||
break;
|
||||
}
|
||||
case ValueType::UTCDate: {
|
||||
|
@ -566,22 +570,23 @@ uint8_t* Builder::set (Value const& item) {
|
|||
v = toInt64(item.getUInt64());
|
||||
break;
|
||||
default:
|
||||
throw Exception(Exception::BuilderUnexpectedValue, "Must give number for ValueType::UTCDate");
|
||||
throw Exception(Exception::BuilderUnexpectedValue,
|
||||
"Must give number for ValueType::UTCDate");
|
||||
}
|
||||
addUTCDate(v);
|
||||
break;
|
||||
}
|
||||
case ValueType::String: {
|
||||
if (ctype != Value::CType::String &&
|
||||
ctype != Value::CType::CharPtr) {
|
||||
throw Exception(Exception::BuilderUnexpectedValue, "Must give a string or char const* for ValueType::String");
|
||||
if (ctype != Value::CType::String && ctype != Value::CType::CharPtr) {
|
||||
throw Exception(
|
||||
Exception::BuilderUnexpectedValue,
|
||||
"Must give a string or char const* for ValueType::String");
|
||||
}
|
||||
std::string const* s;
|
||||
std::string value;
|
||||
if (ctype == Value::CType::String) {
|
||||
s = item.getString();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
value = item.getCharPtr();
|
||||
s = &value;
|
||||
}
|
||||
|
@ -591,8 +596,7 @@ uint8_t* Builder::set (Value const& item) {
|
|||
reserveSpace(1 + size);
|
||||
_start[_pos++] = static_cast<uint8_t>(0x40 + size);
|
||||
memcpy(_start + _pos, s->c_str(), size);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// long string
|
||||
reserveSpace(1 + 8 + size);
|
||||
_start[_pos++] = 0xbf;
|
||||
|
@ -611,16 +615,16 @@ uint8_t* Builder::set (Value const& item) {
|
|||
break;
|
||||
}
|
||||
case ValueType::Binary: {
|
||||
if (ctype != Value::CType::String &&
|
||||
ctype != Value::CType::CharPtr) {
|
||||
throw Exception(Exception::BuilderUnexpectedValue, "Must provide std::string or char const* for ValueType::Binary");
|
||||
if (ctype != Value::CType::String && ctype != Value::CType::CharPtr) {
|
||||
throw Exception(
|
||||
Exception::BuilderUnexpectedValue,
|
||||
"Must provide std::string or char const* for ValueType::Binary");
|
||||
}
|
||||
std::string const* s;
|
||||
std::string value;
|
||||
if (ctype == Value::CType::String) {
|
||||
s = item.getString();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
value = item.getCharPtr();
|
||||
s = &value;
|
||||
}
|
||||
|
@ -644,13 +648,14 @@ uint8_t* Builder::set (Value const& item) {
|
|||
throw Exception(Exception::NotImplemented);
|
||||
}
|
||||
case ValueType::Custom: {
|
||||
throw Exception(Exception::BuilderUnexpectedType, "Cannot set a ValueType::Custom with this method");
|
||||
throw Exception(Exception::BuilderUnexpectedType,
|
||||
"Cannot set a ValueType::Custom with this method");
|
||||
}
|
||||
}
|
||||
return oldPos;
|
||||
}
|
||||
|
||||
uint8_t* Builder::set (Slice const& item) {
|
||||
uint8_t* Builder::set(Slice const& item) {
|
||||
ValueLength const l = item.byteSize();
|
||||
reserveSpace(l);
|
||||
memcpy(_start + _pos, item.start(), l);
|
||||
|
@ -658,7 +663,7 @@ uint8_t* Builder::set (Slice const& item) {
|
|||
return _start + _pos - l;
|
||||
}
|
||||
|
||||
uint8_t* Builder::set (ValuePair const& pair) {
|
||||
uint8_t* Builder::set(ValuePair const& pair) {
|
||||
// This method builds a single further VPack item at the current
|
||||
// append position. This is the case for ValueType::ID or
|
||||
// ValueType::Binary, which both need two pieces of information
|
||||
|
@ -669,29 +674,26 @@ uint8_t* Builder::set (ValuePair const& pair) {
|
|||
memcpy(_start + _pos, pair.getStart(), v);
|
||||
_pos += v;
|
||||
return nullptr; // unused here
|
||||
}
|
||||
else if (pair.valueType() == ValueType::String) {
|
||||
} else if (pair.valueType() == ValueType::String) {
|
||||
uint64_t size = pair.getSize();
|
||||
if (size > 126) {
|
||||
if (size > 126) {
|
||||
// long string
|
||||
reserveSpace(1 + 8 + size);
|
||||
_start[_pos++] = 0xbf;
|
||||
appendLength(size, 8);
|
||||
_pos += size;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// short string
|
||||
reserveSpace(1 + size);
|
||||
_start[_pos++] = static_cast<uint8_t>(0x40 + size);
|
||||
_pos += size;
|
||||
}
|
||||
// Note that the data is not filled in! It is the responsibility
|
||||
// of the caller to fill in
|
||||
// of the caller to fill in
|
||||
// _start + _pos - size .. _start + _pos - 1
|
||||
// with valid UTF-8!
|
||||
return _start + _pos - size;
|
||||
}
|
||||
else if (pair.valueType() == ValueType::Custom) {
|
||||
} else if (pair.valueType() == ValueType::Custom) {
|
||||
// We only reserve space here, the caller has to fill in the custom type
|
||||
uint64_t size = pair.getSize();
|
||||
reserveSpace(size);
|
||||
|
@ -702,10 +704,12 @@ uint8_t* Builder::set (ValuePair const& pair) {
|
|||
_pos += size;
|
||||
return _start + _pos - size;
|
||||
}
|
||||
throw Exception(Exception::BuilderUnexpectedType, "Only ValueType::Binary, ValueType::String and ValueType::Custom are valid for ValuePair argument");
|
||||
throw Exception(Exception::BuilderUnexpectedType,
|
||||
"Only ValueType::Binary, ValueType::String and "
|
||||
"ValueType::Custom are valid for ValuePair argument");
|
||||
}
|
||||
|
||||
void Builder::checkAttributeUniqueness (Slice const& obj) const {
|
||||
void Builder::checkAttributeUniqueness(Slice const& obj) const {
|
||||
VELOCYPACK_ASSERT(options->checkAttributeUniqueness == true);
|
||||
ValueLength const n = obj.length();
|
||||
|
||||
|
@ -718,10 +722,11 @@ void Builder::checkAttributeUniqueness (Slice const& obj) const {
|
|||
// compare each two adjacent attribute names
|
||||
for (ValueLength i = 1; i < n; ++i) {
|
||||
Slice current = obj.keyAt(i);
|
||||
if (! current.isString()) {
|
||||
throw Exception(Exception::BuilderUnexpectedType, "Expecting String key");
|
||||
if (!current.isString()) {
|
||||
throw Exception(Exception::BuilderUnexpectedType,
|
||||
"Expecting String key");
|
||||
}
|
||||
|
||||
|
||||
ValueLength len2;
|
||||
char const* q = current.getString(len2);
|
||||
|
||||
|
@ -733,46 +738,41 @@ void Builder::checkAttributeUniqueness (Slice const& obj) const {
|
|||
len = len2;
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
std::unordered_set<std::string> keys;
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
Slice key = obj.keyAt(i);
|
||||
if (! key.isString()) {
|
||||
throw Exception(Exception::BuilderUnexpectedType, "Expecting String key");
|
||||
if (!key.isString()) {
|
||||
throw Exception(Exception::BuilderUnexpectedType,
|
||||
"Expecting String key");
|
||||
}
|
||||
|
||||
if (! keys.emplace(key.copyString()).second) {
|
||||
|
||||
if (!keys.emplace(key.copyString()).second) {
|
||||
throw Exception(Exception::DuplicateAttributeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* Builder::add (std::string const& attrName, Value const& sub) {
|
||||
uint8_t* Builder::add(std::string const& attrName, Value const& sub) {
|
||||
return addInternal<Value>(attrName, sub);
|
||||
}
|
||||
|
||||
uint8_t* Builder::add (std::string const& attrName, ValuePair const& sub) {
|
||||
uint8_t* Builder::add(std::string const& attrName, ValuePair const& sub) {
|
||||
return addInternal<ValuePair>(attrName, sub);
|
||||
}
|
||||
|
||||
uint8_t* Builder::add (std::string const& attrName, Slice const& sub) {
|
||||
uint8_t* Builder::add(std::string const& attrName, Slice const& sub) {
|
||||
return addInternal<Slice>(attrName, sub);
|
||||
}
|
||||
|
||||
uint8_t* Builder::add (Value const& sub) {
|
||||
return addInternal<Value>(sub);
|
||||
}
|
||||
uint8_t* Builder::add(Value const& sub) { return addInternal<Value>(sub); }
|
||||
|
||||
uint8_t* Builder::add (ValuePair const& sub) {
|
||||
uint8_t* Builder::add(ValuePair const& sub) {
|
||||
return addInternal<ValuePair>(sub);
|
||||
}
|
||||
|
||||
uint8_t* Builder::add (Slice const& sub) {
|
||||
return addInternal<Slice>(sub);
|
||||
}
|
||||
uint8_t* Builder::add(Slice const& sub) { return addInternal<Slice>(sub); }
|
||||
|
||||
static_assert(sizeof(double) == 8, "double is not 8 bytes");
|
||||
|
||||
|
|
|
@ -36,20 +36,23 @@
|
|||
using namespace arangodb::velocypack;
|
||||
|
||||
// convert a vector of strings into an unordered_set of strings
|
||||
static inline std::unordered_set<std::string> ToSet (std::vector<std::string> const& keys) {
|
||||
static inline std::unordered_set<std::string> ToSet(
|
||||
std::vector<std::string> const& keys) {
|
||||
std::unordered_set<std::string> s;
|
||||
for (auto const& it : keys) {
|
||||
s.emplace(it);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void Collection::forEach (Slice const& slice, std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
void Collection::forEach(
|
||||
Slice const& slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
ArrayIterator it(slice);
|
||||
ValueLength index = 0;
|
||||
|
||||
while (it.valid()) {
|
||||
if (! cb(it.value(), index)) {
|
||||
if (!cb(it.value(), index)) {
|
||||
// abort
|
||||
return;
|
||||
}
|
||||
|
@ -57,8 +60,10 @@ void Collection::forEach (Slice const& slice, std::function<bool(Slice const&, V
|
|||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
Builder Collection::filter (Slice const& slice, std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
|
||||
Builder Collection::filter(
|
||||
Slice const& slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
// construct a new Array
|
||||
Builder b;
|
||||
b.add(Value(ValueType::Array));
|
||||
|
@ -77,8 +82,10 @@ Builder Collection::filter (Slice const& slice, std::function<bool(Slice const&,
|
|||
b.close();
|
||||
return b;
|
||||
}
|
||||
|
||||
Slice Collection::find (Slice const& slice, std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
|
||||
Slice Collection::find(
|
||||
Slice const& slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
ArrayIterator it(slice);
|
||||
ValueLength index = 0;
|
||||
|
||||
|
@ -93,8 +100,10 @@ Slice Collection::find (Slice const& slice, std::function<bool(Slice const&, Val
|
|||
|
||||
return Slice();
|
||||
}
|
||||
|
||||
bool Collection::contains (Slice const& slice, std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
|
||||
bool Collection::contains(
|
||||
Slice const& slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
ArrayIterator it(slice);
|
||||
ValueLength index = 0;
|
||||
|
||||
|
@ -109,14 +118,15 @@ bool Collection::contains (Slice const& slice, std::function<bool(Slice const&,
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Collection::all (Slice const& slice, std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
|
||||
bool Collection::all(Slice const& slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
ArrayIterator it(slice);
|
||||
ValueLength index = 0;
|
||||
|
||||
while (it.valid()) {
|
||||
Slice s = it.value();
|
||||
if (! cb(s, index)) {
|
||||
if (!cb(s, index)) {
|
||||
return false;
|
||||
}
|
||||
it.next();
|
||||
|
@ -125,8 +135,9 @@ bool Collection::all (Slice const& slice, std::function<bool(Slice const&, Value
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Collection::any (Slice const& slice, std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
|
||||
bool Collection::any(Slice const& slice,
|
||||
std::function<bool(Slice const&, ValueLength)> const& cb) {
|
||||
ArrayIterator it(slice);
|
||||
ValueLength index = 0;
|
||||
|
||||
|
@ -141,16 +152,16 @@ bool Collection::any (Slice const& slice, std::function<bool(Slice const&, Value
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> Collection::keys (Slice const& slice) {
|
||||
|
||||
std::vector<std::string> Collection::keys(Slice const& slice) {
|
||||
std::vector<std::string> result;
|
||||
|
||||
keys(slice, result);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Collection::keys (Slice const& slice, std::vector<std::string>& result) {
|
||||
|
||||
void Collection::keys(Slice const& slice, std::vector<std::string>& result) {
|
||||
// pre-allocate result vector
|
||||
result.reserve(slice.length());
|
||||
|
||||
|
@ -161,8 +172,9 @@ void Collection::keys (Slice const& slice, std::vector<std::string>& result) {
|
|||
it.next();
|
||||
}
|
||||
}
|
||||
|
||||
void Collection::keys (Slice const& slice, std::unordered_set<std::string>& result) {
|
||||
|
||||
void Collection::keys(Slice const& slice,
|
||||
std::unordered_set<std::string>& result) {
|
||||
ObjectIterator it(slice);
|
||||
|
||||
while (it.valid()) {
|
||||
|
@ -171,7 +183,7 @@ void Collection::keys (Slice const& slice, std::unordered_set<std::string>& resu
|
|||
}
|
||||
}
|
||||
|
||||
Builder Collection::values (Slice const& slice) {
|
||||
Builder Collection::values(Slice const& slice) {
|
||||
Builder b;
|
||||
b.add(Value(ValueType::Array));
|
||||
|
||||
|
@ -186,7 +198,8 @@ Builder Collection::values (Slice const& slice) {
|
|||
return b;
|
||||
}
|
||||
|
||||
Builder Collection::keep (Slice const& slice, std::vector<std::string> const& keys) {
|
||||
Builder Collection::keep(Slice const& slice,
|
||||
std::vector<std::string> const& keys) {
|
||||
// check if there are so many keys that we want to use the hash-based version
|
||||
// cut-off values are arbitrary...
|
||||
if (keys.size() >= 4 && slice.length() > 10) {
|
||||
|
@ -210,7 +223,8 @@ Builder Collection::keep (Slice const& slice, std::vector<std::string> const& ke
|
|||
return b;
|
||||
}
|
||||
|
||||
Builder Collection::keep (Slice const& slice, std::unordered_set<std::string> const& keys) {
|
||||
Builder Collection::keep(Slice const& slice,
|
||||
std::unordered_set<std::string> const& keys) {
|
||||
Builder b;
|
||||
b.add(Value(ValueType::Object));
|
||||
|
||||
|
@ -228,7 +242,8 @@ Builder Collection::keep (Slice const& slice, std::unordered_set<std::string> co
|
|||
return b;
|
||||
}
|
||||
|
||||
Builder Collection::remove (Slice const& slice, std::vector<std::string> const& keys) {
|
||||
Builder Collection::remove(Slice const& slice,
|
||||
std::vector<std::string> const& keys) {
|
||||
// check if there are so many keys that we want to use the hash-based version
|
||||
// cut-off values are arbitrary...
|
||||
if (keys.size() >= 4 && slice.length() > 10) {
|
||||
|
@ -252,7 +267,8 @@ Builder Collection::remove (Slice const& slice, std::vector<std::string> const&
|
|||
return b;
|
||||
}
|
||||
|
||||
Builder Collection::remove (Slice const& slice, std::unordered_set<std::string> const& keys) {
|
||||
Builder Collection::remove(Slice const& slice,
|
||||
std::unordered_set<std::string> const& keys) {
|
||||
Builder b;
|
||||
b.add(Value(ValueType::Object));
|
||||
|
||||
|
@ -270,14 +286,15 @@ Builder Collection::remove (Slice const& slice, std::unordered_set<std::string>
|
|||
return b;
|
||||
}
|
||||
|
||||
Builder Collection::merge (Slice const& left, Slice const& right, bool mergeValues) {
|
||||
if (! left.isObject() || ! right.isObject()) {
|
||||
Builder Collection::merge(Slice const& left, Slice const& right,
|
||||
bool mergeValues) {
|
||||
if (!left.isObject() || !right.isObject()) {
|
||||
throw Exception(Exception::InvalidValueType, "Expecting type Object");
|
||||
}
|
||||
|
||||
Builder b;
|
||||
b.add(Value(ValueType::Object));
|
||||
|
||||
|
||||
std::unordered_map<std::string, Slice> rightValues;
|
||||
{
|
||||
ObjectIterator it(right);
|
||||
|
@ -286,10 +303,10 @@ Builder Collection::merge (Slice const& left, Slice const& right, bool mergeValu
|
|||
it.next();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
{
|
||||
ObjectIterator it(left);
|
||||
|
||||
|
||||
while (it.valid()) {
|
||||
auto key = std::move(it.key().copyString());
|
||||
auto found = rightValues.find(key);
|
||||
|
@ -297,17 +314,16 @@ Builder Collection::merge (Slice const& left, Slice const& right, bool mergeValu
|
|||
if (found == rightValues.end()) {
|
||||
// use left value
|
||||
b.add(key, it.value());
|
||||
}
|
||||
else if (mergeValues && it.value().isObject() && (*found).second.isObject()) {
|
||||
} else if (mergeValues && it.value().isObject() &&
|
||||
(*found).second.isObject()) {
|
||||
// merge both values
|
||||
Builder sub = Collection::merge(it.value(), (*found).second, true);
|
||||
Builder sub = Collection::merge(it.value(), (*found).second, true);
|
||||
b.add(key, sub.slice());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// use right value
|
||||
b.add(key, (*found).second);
|
||||
// clear the value in the map so its not added again
|
||||
(*found).second = Slice();
|
||||
(*found).second = Slice();
|
||||
}
|
||||
it.next();
|
||||
}
|
||||
|
@ -316,20 +332,24 @@ Builder Collection::merge (Slice const& left, Slice const& right, bool mergeValu
|
|||
// add remaining values that were only in right
|
||||
for (auto& it : rightValues) {
|
||||
auto s = it.second;
|
||||
if (! s.isNone()) {
|
||||
if (!s.isNone()) {
|
||||
b.add(std::move(it.first), it.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b.close();
|
||||
return b;
|
||||
}
|
||||
|
||||
template<Collection::VisitationOrder order>
|
||||
static bool doVisit (Slice const& slice, std::function<bool(Slice const& key, Slice const& value)> const& func);
|
||||
template <Collection::VisitationOrder order>
|
||||
static bool doVisit(
|
||||
Slice const& slice,
|
||||
std::function<bool(Slice const& key, Slice const& value)> const& func);
|
||||
|
||||
template<Collection::VisitationOrder order>
|
||||
static bool visitObject (Slice const& value, std::function<bool(Slice const& key, Slice const& value)> const& func) {
|
||||
template <Collection::VisitationOrder order>
|
||||
static bool visitObject(
|
||||
Slice const& value,
|
||||
std::function<bool(Slice const& key, Slice const& value)> const& func) {
|
||||
ObjectIterator it(value);
|
||||
|
||||
while (it.valid()) {
|
||||
|
@ -338,17 +358,17 @@ static bool visitObject (Slice const& value, std::function<bool(Slice const& key
|
|||
bool const isCompound = (v.isObject() || v.isArray());
|
||||
|
||||
if (isCompound && order == Collection::PreOrder) {
|
||||
if (! doVisit<order>(v, func)) {
|
||||
if (!doVisit<order>(v, func)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! func(it.key(), v)) {
|
||||
if (!func(it.key(), v)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isCompound && order == Collection::PostOrder) {
|
||||
if (! doVisit<order>(v, func)) {
|
||||
if (!doVisit<order>(v, func)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -358,8 +378,10 @@ static bool visitObject (Slice const& value, std::function<bool(Slice const& key
|
|||
return true;
|
||||
}
|
||||
|
||||
template<Collection::VisitationOrder order>
|
||||
static bool visitArray (Slice const& value, std::function<bool(Slice const& key, Slice const& value)> const& func) {
|
||||
template <Collection::VisitationOrder order>
|
||||
static bool visitArray(
|
||||
Slice const& value,
|
||||
std::function<bool(Slice const& key, Slice const& value)> const& func) {
|
||||
ArrayIterator it(value);
|
||||
|
||||
while (it.valid()) {
|
||||
|
@ -368,17 +390,17 @@ static bool visitArray (Slice const& value, std::function<bool(Slice const& key,
|
|||
bool const isCompound = (v.isObject() || v.isArray());
|
||||
|
||||
if (isCompound && order == Collection::PreOrder) {
|
||||
if (! doVisit<order>(v, func)) {
|
||||
if (!doVisit<order>(v, func)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! func(Slice(), v)) {
|
||||
if (!func(Slice(), v)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isCompound && order == Collection::PostOrder) {
|
||||
if (! doVisit<order>(v, func)) {
|
||||
if (!doVisit<order>(v, func)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -386,11 +408,13 @@ static bool visitArray (Slice const& value, std::function<bool(Slice const& key,
|
|||
it.next();
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<Collection::VisitationOrder order>
|
||||
static bool doVisit (Slice const& slice, std::function<bool(Slice const& key, Slice const& value)> const& func) {
|
||||
template <Collection::VisitationOrder order>
|
||||
static bool doVisit(
|
||||
Slice const& slice,
|
||||
std::function<bool(Slice const& key, Slice const& value)> const& func) {
|
||||
if (slice.isObject()) {
|
||||
return visitObject<order>(slice, func);
|
||||
}
|
||||
|
@ -398,15 +422,16 @@ static bool doVisit (Slice const& slice, std::function<bool(Slice const& key, Sl
|
|||
return visitArray<order>(slice, func);
|
||||
}
|
||||
|
||||
throw Exception(Exception::InvalidValueType, "Expecting type Object or Array");
|
||||
throw Exception(Exception::InvalidValueType,
|
||||
"Expecting type Object or Array");
|
||||
}
|
||||
|
||||
void Collection::visitRecursive (Slice const& slice, Collection::VisitationOrder order, std::function<bool(Slice const&, Slice const&)> const& func) {
|
||||
void Collection::visitRecursive(
|
||||
Slice const& slice, Collection::VisitationOrder order,
|
||||
std::function<bool(Slice const&, Slice const&)> const& func) {
|
||||
if (order == Collection::PreOrder) {
|
||||
doVisit<Collection::PreOrder>(slice, func);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
doVisit<Collection::PostOrder>(slice, func);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,47 +30,84 @@
|
|||
#include "velocypack/Dumper.h"
|
||||
#include "velocypack/Iterator.h"
|
||||
#include "velocypack/ValueType.h"
|
||||
|
||||
|
||||
using namespace arangodb::velocypack;
|
||||
|
||||
// forward for fpconv function declared elsewhere
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
int fpconv_dtoa (double fp, char dest[24]);
|
||||
}
|
||||
namespace velocypack {
|
||||
int fpconv_dtoa(double fp, char dest[24]);
|
||||
}
|
||||
};
|
||||
|
||||
void Dumper::appendUInt (uint64_t v) {
|
||||
if (10000000000000000000ULL <= v) { _sink->push_back('0' + (v / 10000000000000000000ULL) % 10); }
|
||||
if ( 1000000000000000000ULL <= v) { _sink->push_back('0' + (v / 1000000000000000000ULL) % 10); }
|
||||
if ( 100000000000000000ULL <= v) { _sink->push_back('0' + (v / 100000000000000000ULL) % 10); }
|
||||
if ( 10000000000000000ULL <= v) { _sink->push_back('0' + (v / 10000000000000000ULL) % 10); }
|
||||
if ( 1000000000000000ULL <= v) { _sink->push_back('0' + (v / 1000000000000000ULL) % 10); }
|
||||
if ( 100000000000000ULL <= v) { _sink->push_back('0' + (v / 100000000000000ULL) % 10); }
|
||||
if ( 10000000000000ULL <= v) { _sink->push_back('0' + (v / 10000000000000ULL) % 10); }
|
||||
if ( 1000000000000ULL <= v) { _sink->push_back('0' + (v / 1000000000000ULL) % 10); }
|
||||
if ( 100000000000ULL <= v) { _sink->push_back('0' + (v / 100000000000ULL) % 10); }
|
||||
if ( 10000000000ULL <= v) { _sink->push_back('0' + (v / 10000000000ULL) % 10); }
|
||||
if ( 1000000000ULL <= v) { _sink->push_back('0' + (v / 1000000000ULL) % 10); }
|
||||
if ( 100000000ULL <= v) { _sink->push_back('0' + (v / 100000000ULL) % 10); }
|
||||
if ( 10000000ULL <= v) { _sink->push_back('0' + (v / 10000000ULL) % 10); }
|
||||
if ( 1000000ULL <= v) { _sink->push_back('0' + (v / 1000000ULL) % 10); }
|
||||
if ( 100000ULL <= v) { _sink->push_back('0' + (v / 100000ULL) % 10); }
|
||||
if ( 10000ULL <= v) { _sink->push_back('0' + (v / 10000ULL) % 10); }
|
||||
if ( 1000ULL <= v) { _sink->push_back('0' + (v / 1000ULL) % 10); }
|
||||
if ( 100ULL <= v) { _sink->push_back('0' + (v / 100ULL) % 10); }
|
||||
if ( 10ULL <= v) { _sink->push_back('0' + (v / 10ULL) % 10); }
|
||||
void Dumper::appendUInt(uint64_t v) {
|
||||
if (10000000000000000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 10000000000000000000ULL) % 10);
|
||||
}
|
||||
if (1000000000000000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 1000000000000000000ULL) % 10);
|
||||
}
|
||||
if (100000000000000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 100000000000000000ULL) % 10);
|
||||
}
|
||||
if (10000000000000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 10000000000000000ULL) % 10);
|
||||
}
|
||||
if (1000000000000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 1000000000000000ULL) % 10);
|
||||
}
|
||||
if (100000000000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 100000000000000ULL) % 10);
|
||||
}
|
||||
if (10000000000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 10000000000000ULL) % 10);
|
||||
}
|
||||
if (1000000000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 1000000000000ULL) % 10);
|
||||
}
|
||||
if (100000000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 100000000000ULL) % 10);
|
||||
}
|
||||
if (10000000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 10000000000ULL) % 10);
|
||||
}
|
||||
if (1000000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 1000000000ULL) % 10);
|
||||
}
|
||||
if (100000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 100000000ULL) % 10);
|
||||
}
|
||||
if (10000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 10000000ULL) % 10);
|
||||
}
|
||||
if (1000000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 1000000ULL) % 10);
|
||||
}
|
||||
if (100000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 100000ULL) % 10);
|
||||
}
|
||||
if (10000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 10000ULL) % 10);
|
||||
}
|
||||
if (1000ULL <= v) {
|
||||
_sink->push_back('0' + (v / 1000ULL) % 10);
|
||||
}
|
||||
if (100ULL <= v) {
|
||||
_sink->push_back('0' + (v / 100ULL) % 10);
|
||||
}
|
||||
if (10ULL <= v) {
|
||||
_sink->push_back('0' + (v / 10ULL) % 10);
|
||||
}
|
||||
|
||||
_sink->push_back('0' + (v % 10));
|
||||
}
|
||||
|
||||
void Dumper::dumpInteger (Slice const* slice) {
|
||||
|
||||
void Dumper::dumpInteger(Slice const* slice) {
|
||||
if (slice->isType(ValueType::UInt)) {
|
||||
uint64_t v = slice->getUInt();
|
||||
|
||||
appendUInt(v);
|
||||
}
|
||||
else if (slice->isType(ValueType::Int)) {
|
||||
} else if (slice->isType(ValueType::Int)) {
|
||||
int64_t v = slice->getInt();
|
||||
if (v == INT64_MIN) {
|
||||
_sink->append("-9223372036854775808", 20);
|
||||
|
@ -80,61 +117,109 @@ void Dumper::dumpInteger (Slice const* slice) {
|
|||
_sink->push_back('-');
|
||||
v = -v;
|
||||
}
|
||||
|
||||
if (1000000000000000000LL <= v) { _sink->push_back('0' + (v / 1000000000000000000LL) % 10); }
|
||||
if ( 100000000000000000LL <= v) { _sink->push_back('0' + (v / 100000000000000000LL) % 10); }
|
||||
if ( 10000000000000000LL <= v) { _sink->push_back('0' + (v / 10000000000000000LL) % 10); }
|
||||
if ( 1000000000000000LL <= v) { _sink->push_back('0' + (v / 1000000000000000LL) % 10); }
|
||||
if ( 100000000000000LL <= v) { _sink->push_back('0' + (v / 100000000000000LL) % 10); }
|
||||
if ( 10000000000000LL <= v) { _sink->push_back('0' + (v / 10000000000000LL) % 10); }
|
||||
if ( 1000000000000LL <= v) { _sink->push_back('0' + (v / 1000000000000LL) % 10); }
|
||||
if ( 100000000000LL <= v) { _sink->push_back('0' + (v / 100000000000LL) % 10); }
|
||||
if ( 10000000000LL <= v) { _sink->push_back('0' + (v / 10000000000LL) % 10); }
|
||||
if ( 1000000000LL <= v) { _sink->push_back('0' + (v / 1000000000LL) % 10); }
|
||||
if ( 100000000LL <= v) { _sink->push_back('0' + (v / 100000000LL) % 10); }
|
||||
if ( 10000000LL <= v) { _sink->push_back('0' + (v / 10000000LL) % 10); }
|
||||
if ( 1000000LL <= v) { _sink->push_back('0' + (v / 1000000LL) % 10); }
|
||||
if ( 100000LL <= v) { _sink->push_back('0' + (v / 100000LL) % 10); }
|
||||
if ( 10000LL <= v) { _sink->push_back('0' + (v / 10000LL) % 10); }
|
||||
if ( 1000LL <= v) { _sink->push_back('0' + (v / 1000LL) % 10); }
|
||||
if ( 100LL <= v) { _sink->push_back('0' + (v / 100LL) % 10); }
|
||||
if ( 10LL <= v) { _sink->push_back('0' + (v / 10LL) % 10); }
|
||||
|
||||
if (1000000000000000000LL <= v) {
|
||||
_sink->push_back('0' + (v / 1000000000000000000LL) % 10);
|
||||
}
|
||||
if (100000000000000000LL <= v) {
|
||||
_sink->push_back('0' + (v / 100000000000000000LL) % 10);
|
||||
}
|
||||
if (10000000000000000LL <= v) {
|
||||
_sink->push_back('0' + (v / 10000000000000000LL) % 10);
|
||||
}
|
||||
if (1000000000000000LL <= v) {
|
||||
_sink->push_back('0' + (v / 1000000000000000LL) % 10);
|
||||
}
|
||||
if (100000000000000LL <= v) {
|
||||
_sink->push_back('0' + (v / 100000000000000LL) % 10);
|
||||
}
|
||||
if (10000000000000LL <= v) {
|
||||
_sink->push_back('0' + (v / 10000000000000LL) % 10);
|
||||
}
|
||||
if (1000000000000LL <= v) {
|
||||
_sink->push_back('0' + (v / 1000000000000LL) % 10);
|
||||
}
|
||||
if (100000000000LL <= v) {
|
||||
_sink->push_back('0' + (v / 100000000000LL) % 10);
|
||||
}
|
||||
if (10000000000LL <= v) {
|
||||
_sink->push_back('0' + (v / 10000000000LL) % 10);
|
||||
}
|
||||
if (1000000000LL <= v) {
|
||||
_sink->push_back('0' + (v / 1000000000LL) % 10);
|
||||
}
|
||||
if (100000000LL <= v) {
|
||||
_sink->push_back('0' + (v / 100000000LL) % 10);
|
||||
}
|
||||
if (10000000LL <= v) {
|
||||
_sink->push_back('0' + (v / 10000000LL) % 10);
|
||||
}
|
||||
if (1000000LL <= v) {
|
||||
_sink->push_back('0' + (v / 1000000LL) % 10);
|
||||
}
|
||||
if (100000LL <= v) {
|
||||
_sink->push_back('0' + (v / 100000LL) % 10);
|
||||
}
|
||||
if (10000LL <= v) {
|
||||
_sink->push_back('0' + (v / 10000LL) % 10);
|
||||
}
|
||||
if (1000LL <= v) {
|
||||
_sink->push_back('0' + (v / 1000LL) % 10);
|
||||
}
|
||||
if (100LL <= v) {
|
||||
_sink->push_back('0' + (v / 100LL) % 10);
|
||||
}
|
||||
if (10LL <= v) {
|
||||
_sink->push_back('0' + (v / 10LL) % 10);
|
||||
}
|
||||
|
||||
_sink->push_back('0' + (v % 10));
|
||||
}
|
||||
else if (slice->isType(ValueType::SmallInt)) {
|
||||
} else if (slice->isType(ValueType::SmallInt)) {
|
||||
int64_t v = slice->getSmallInt();
|
||||
if (v < 0) {
|
||||
_sink->push_back('-');
|
||||
v = -v;
|
||||
}
|
||||
_sink->push_back('0' + static_cast<char>(v));
|
||||
}
|
||||
else {
|
||||
throw Exception(Exception::InternalError, "Unexpected number type");
|
||||
} else {
|
||||
// we should never get here
|
||||
throw Exception(Exception::InvalidValueType, "Unexpected number type");
|
||||
}
|
||||
}
|
||||
|
||||
void Dumper::dumpString (char const* src, ValueLength len) {
|
||||
void Dumper::dumpString(char const* src, ValueLength len) {
|
||||
static char const EscapeTable[256] = {
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
|
||||
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/', // 20
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 30~4F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60~FF
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E
|
||||
// F
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r',
|
||||
'u',
|
||||
'u', // 00
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
|
||||
'u',
|
||||
'u', // 10
|
||||
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
'/', // 20
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
0, // 30~4F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
'\\', 0, 0, 0, // 50
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
0, // 60~FF
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0};
|
||||
|
||||
uint8_t const* p = reinterpret_cast<uint8_t const*>(src);
|
||||
uint8_t const* e = p + len;
|
||||
|
@ -152,20 +237,20 @@ void Dumper::dumpString (char const* src, ValueLength len) {
|
|||
}
|
||||
_sink->push_back(static_cast<char>(esc));
|
||||
|
||||
if (esc == 'u') {
|
||||
uint16_t i1 = (((uint16_t) c) & 0xf0) >> 4;
|
||||
uint16_t i2 = (((uint16_t) c) & 0x0f);
|
||||
if (esc == 'u') {
|
||||
uint16_t i1 = (((uint16_t)c) & 0xf0) >> 4;
|
||||
uint16_t i2 = (((uint16_t)c) & 0x0f);
|
||||
|
||||
_sink->append("00", 2);
|
||||
_sink->push_back(static_cast<char>((i1 < 10) ? ('0' + i1) : ('A' + i1 - 10)));
|
||||
_sink->push_back(static_cast<char>((i2 < 10) ? ('0' + i2) : ('A' + i2 - 10)));
|
||||
_sink->push_back(
|
||||
static_cast<char>((i1 < 10) ? ('0' + i1) : ('A' + i1 - 10)));
|
||||
_sink->push_back(
|
||||
static_cast<char>((i2 < 10) ? ('0' + i2) : ('A' + i2 - 10)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
_sink->push_back(static_cast<char>(c));
|
||||
}
|
||||
}
|
||||
else if ((c & 0xe0) == 0xc0) {
|
||||
} else if ((c & 0xe0) == 0xc0) {
|
||||
// two-byte sequence
|
||||
if (p + 1 >= e) {
|
||||
throw Exception(Exception::InvalidUtf8Sequence);
|
||||
|
@ -173,8 +258,7 @@ void Dumper::dumpString (char const* src, ValueLength len) {
|
|||
|
||||
_sink->append(reinterpret_cast<char const*>(p), 2);
|
||||
++p;
|
||||
}
|
||||
else if ((c & 0xf0) == 0xe0) {
|
||||
} else if ((c & 0xf0) == 0xe0) {
|
||||
// three-byte sequence
|
||||
if (p + 2 >= e) {
|
||||
throw Exception(Exception::InvalidUtf8Sequence);
|
||||
|
@ -182,8 +266,7 @@ void Dumper::dumpString (char const* src, ValueLength len) {
|
|||
|
||||
_sink->append(reinterpret_cast<char const*>(p), 3);
|
||||
p += 2;
|
||||
}
|
||||
else if ((c & 0xf8) == 0xf0) {
|
||||
} else if ((c & 0xf8) == 0xf0) {
|
||||
// four-byte sequence
|
||||
if (p + 3 >= e) {
|
||||
throw Exception(Exception::InvalidUtf8Sequence);
|
||||
|
@ -196,17 +279,17 @@ void Dumper::dumpString (char const* src, ValueLength len) {
|
|||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
void Dumper::dumpValue (Slice const* slice, Slice const* base) {
|
||||
|
||||
void Dumper::dumpValue(Slice const* slice, Slice const* base) {
|
||||
if (base == nullptr) {
|
||||
base = slice;
|
||||
VELOCYPACK_ASSERT(base != nullptr);
|
||||
}
|
||||
|
||||
|
||||
switch (slice->type()) {
|
||||
case ValueType::None: {
|
||||
handleUnsupportedType(slice);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
case ValueType::Null: {
|
||||
|
@ -217,8 +300,7 @@ void Dumper::dumpValue (Slice const* slice, Slice const* base) {
|
|||
case ValueType::Bool: {
|
||||
if (slice->getBool()) {
|
||||
_sink->append("true", 4);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
_sink->append("false", 5);
|
||||
}
|
||||
break;
|
||||
|
@ -233,7 +315,7 @@ void Dumper::dumpValue (Slice const* slice, Slice const* base) {
|
|||
while (it.valid()) {
|
||||
indent();
|
||||
dumpValue(it.value(), base);
|
||||
if (! it.isLast()) {
|
||||
if (!it.isLast()) {
|
||||
_sink->push_back(',');
|
||||
}
|
||||
_sink->push_back('\n');
|
||||
|
@ -241,10 +323,9 @@ void Dumper::dumpValue (Slice const* slice, Slice const* base) {
|
|||
}
|
||||
--_indentation;
|
||||
indent();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
while (it.valid()) {
|
||||
if (! it.isFirst()) {
|
||||
if (!it.isFirst()) {
|
||||
_sink->push_back(',');
|
||||
}
|
||||
dumpValue(it.value(), base);
|
||||
|
@ -266,7 +347,7 @@ void Dumper::dumpValue (Slice const* slice, Slice const* base) {
|
|||
dumpValue(it.key().makeKey(), base);
|
||||
_sink->append(" : ", 3);
|
||||
dumpValue(it.value(), base);
|
||||
if (! it.isLast()) {
|
||||
if (!it.isLast()) {
|
||||
_sink->push_back(',');
|
||||
}
|
||||
_sink->push_back('\n');
|
||||
|
@ -274,10 +355,9 @@ void Dumper::dumpValue (Slice const* slice, Slice const* base) {
|
|||
}
|
||||
--_indentation;
|
||||
indent();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
while (it.valid()) {
|
||||
if (! it.isFirst()) {
|
||||
if (!it.isFirst()) {
|
||||
_sink->push_back(',');
|
||||
}
|
||||
dumpValue(it.key().makeKey(), base);
|
||||
|
@ -289,20 +369,19 @@ void Dumper::dumpValue (Slice const* slice, Slice const* base) {
|
|||
_sink->push_back('}');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case ValueType::Double: {
|
||||
double const v = slice->getDouble();
|
||||
if (std::isnan(v) || ! std::isfinite(v)) {
|
||||
if (std::isnan(v) || !std::isfinite(v)) {
|
||||
handleUnsupportedType(slice);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
char temp[24];
|
||||
int len = fpconv_dtoa(v, &temp[0]);
|
||||
_sink->append(&temp[0], static_cast<ValueLength>(len));
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case ValueType::UTCDate: {
|
||||
handleUnsupportedType(slice);
|
||||
break;
|
||||
|
@ -313,13 +392,13 @@ void Dumper::dumpValue (Slice const* slice, Slice const* base) {
|
|||
dumpValue(&external, base);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case ValueType::MinKey:
|
||||
case ValueType::MaxKey: {
|
||||
handleUnsupportedType(slice);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case ValueType::Int:
|
||||
case ValueType::UInt:
|
||||
case ValueType::SmallInt: {
|
||||
|
@ -341,17 +420,16 @@ void Dumper::dumpValue (Slice const* slice, Slice const* base) {
|
|||
handleUnsupportedType(slice);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case ValueType::BCD: {
|
||||
// TODO
|
||||
throw Exception(Exception::NotImplemented);
|
||||
}
|
||||
|
||||
|
||||
case ValueType::Custom: {
|
||||
if (options->customTypeHandler == nullptr) {
|
||||
handleUnsupportedType(slice);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
options->customTypeHandler->toJson(*slice, this, *base);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -31,12 +31,11 @@
|
|||
|
||||
using namespace arangodb::velocypack;
|
||||
|
||||
std::ostream& operator<< (std::ostream& stream, Exception const* ex) {
|
||||
std::ostream& operator<<(std::ostream& stream, Exception const* ex) {
|
||||
stream << "[Exception " << ex->what() << "]";
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& stream, Exception const& ex) {
|
||||
std::ostream& operator<<(std::ostream& stream, Exception const& ex) {
|
||||
return operator<<(stream, &ex);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
#include "velocypack/HexDump.h"
|
||||
|
||||
using namespace arangodb::velocypack;
|
||||
|
||||
std::string HexDump::toHex (uint8_t value) {
|
||||
|
||||
std::string HexDump::toHex(uint8_t value) {
|
||||
std::string result("0x");
|
||||
|
||||
uint8_t x = value / 16;
|
||||
|
@ -41,8 +41,8 @@ std::string HexDump::toHex (uint8_t value) {
|
|||
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& stream, HexDump const* hexdump) {
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, HexDump const* hexdump) {
|
||||
int current = 0;
|
||||
|
||||
for (uint8_t it : hexdump->slice) {
|
||||
|
@ -62,7 +62,6 @@ std::ostream& operator<< (std::ostream& stream, HexDump const* hexdump) {
|
|||
return stream;
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& stream, HexDump const& hexdump) {
|
||||
std::ostream& operator<<(std::ostream& stream, HexDump const& hexdump) {
|
||||
return operator<<(stream, &hexdump);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,21 +31,20 @@
|
|||
|
||||
using namespace arangodb::velocypack;
|
||||
|
||||
std::ostream& operator<< (std::ostream& stream, ArrayIterator const* it) {
|
||||
std::ostream& operator<<(std::ostream& stream, ArrayIterator const* it) {
|
||||
stream << "[ArrayIterator " << it->index() << " / " << it->size() << "]";
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& stream, ArrayIterator const& it) {
|
||||
std::ostream& operator<<(std::ostream& stream, ArrayIterator const& it) {
|
||||
return operator<<(stream, &it);
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& stream, ObjectIterator const* it) {
|
||||
std::ostream& operator<<(std::ostream& stream, ObjectIterator const* it) {
|
||||
stream << "[ObjectIterator " << it->index() << " / " << it->size() << "]";
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& stream, ObjectIterator const& it) {
|
||||
std::ostream& operator<<(std::ostream& stream, ObjectIterator const& it) {
|
||||
return operator<<(stream, &it);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,5 @@
|
|||
|
||||
using namespace arangodb::velocypack;
|
||||
|
||||
// default options instance
|
||||
// default options instance
|
||||
Options Options::Defaults;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "asm-functions.h"
|
||||
|
||||
using namespace arangodb::velocypack;
|
||||
|
||||
|
||||
// The following function does the actual parse. It gets bytes
|
||||
// via peek, consume and reset appends the result to the Builder
|
||||
// in _b. Errors are reported via an exception.
|
||||
|
@ -37,13 +37,11 @@ using namespace arangodb::velocypack;
|
|||
// check for parse errors (scan phase) and then one to actually
|
||||
// build the result (build phase).
|
||||
|
||||
ValueLength Parser::parseInternal (bool multi) {
|
||||
_b.options = options; // copy over options
|
||||
ValueLength Parser::parseInternal(bool multi) {
|
||||
_b.options = options; // copy over options
|
||||
|
||||
// skip over optional BOM
|
||||
if (_size >= 3 &&
|
||||
_start[0] == 0xef &&
|
||||
_start[1] == 0xbb &&
|
||||
if (_size >= 3 && _start[0] == 0xef && _start[1] == 0xbb &&
|
||||
_start[2] == 0xbf) {
|
||||
// found UTF-8 BOM. simply skip over it
|
||||
_pos += 3;
|
||||
|
@ -53,36 +51,34 @@ ValueLength Parser::parseInternal (bool multi) {
|
|||
do {
|
||||
parseJson();
|
||||
nr++;
|
||||
while (_pos < _size &&
|
||||
isWhiteSpace(_start[_pos])) {
|
||||
while (_pos < _size && isWhiteSpace(_start[_pos])) {
|
||||
++_pos;
|
||||
}
|
||||
if (! multi && _pos != _size) {
|
||||
if (!multi && _pos != _size) {
|
||||
consume(); // to get error reporting right
|
||||
throw Exception(Exception::ParseError, "Expecting EOF");
|
||||
}
|
||||
}
|
||||
while (multi && _pos < _size);
|
||||
} while (multi && _pos < _size);
|
||||
return nr;
|
||||
}
|
||||
|
||||
// skips over all following whitespace tokens but does not consume the
|
||||
// byte following the whitespace
|
||||
int Parser::skipWhiteSpace (char const* err) {
|
||||
int Parser::skipWhiteSpace(char const* err) {
|
||||
if (_pos >= _size) {
|
||||
throw Exception(Exception::ParseError, err);
|
||||
}
|
||||
uint8_t c = _start[_pos];
|
||||
if (! isWhiteSpace(c)) {
|
||||
if (!isWhiteSpace(c)) {
|
||||
return c;
|
||||
}
|
||||
if (c == ' ') {
|
||||
if (_pos+1 >= _size) {
|
||||
if (_pos + 1 >= _size) {
|
||||
_pos++;
|
||||
throw Exception(Exception::ParseError, err);
|
||||
}
|
||||
c = _start[_pos+1];
|
||||
if (! isWhiteSpace(c)) {
|
||||
c = _start[_pos + 1];
|
||||
if (!isWhiteSpace(c)) {
|
||||
_pos++;
|
||||
return c;
|
||||
}
|
||||
|
@ -97,7 +93,7 @@ int Parser::skipWhiteSpace (char const* err) {
|
|||
}
|
||||
|
||||
// parses a number value
|
||||
void Parser::parseNumber () {
|
||||
void Parser::parseNumber() {
|
||||
ParsedNumber numberValue;
|
||||
bool negative = false;
|
||||
int i = consume();
|
||||
|
@ -110,7 +106,7 @@ void Parser::parseNumber () {
|
|||
if (i < '0' || i > '9') {
|
||||
throw Exception(Exception::ParseError, "Expecting digit");
|
||||
}
|
||||
|
||||
|
||||
if (i != '0') {
|
||||
unconsume();
|
||||
scanDigits(numberValue);
|
||||
|
@ -120,26 +116,21 @@ void Parser::parseNumber () {
|
|||
if (i >= 0) {
|
||||
unconsume();
|
||||
}
|
||||
if (! numberValue.isInteger) {
|
||||
if (!numberValue.isInteger) {
|
||||
if (negative) {
|
||||
_b.addDouble(-numberValue.doubleValue);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
_b.addDouble(numberValue.doubleValue);
|
||||
}
|
||||
}
|
||||
else if (negative) {
|
||||
} else if (negative) {
|
||||
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 {
|
||||
} else {
|
||||
_b.addDouble(-static_cast<double>(numberValue.intValue));
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
_b.addUInt(numberValue.intValue);
|
||||
}
|
||||
return;
|
||||
|
@ -155,9 +146,8 @@ void Parser::parseNumber () {
|
|||
unconsume();
|
||||
fractionalPart = scanDigitsFractional();
|
||||
if (negative) {
|
||||
fractionalPart = - numberValue.asDouble() - fractionalPart;
|
||||
}
|
||||
else {
|
||||
fractionalPart = -numberValue.asDouble() - fractionalPart;
|
||||
} else {
|
||||
fractionalPart = numberValue.asDouble() + fractionalPart;
|
||||
}
|
||||
i = consume();
|
||||
|
@ -165,12 +155,10 @@ void Parser::parseNumber () {
|
|||
_b.addDouble(fractionalPart);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (negative) {
|
||||
fractionalPart = - numberValue.asDouble();
|
||||
}
|
||||
else {
|
||||
fractionalPart = -numberValue.asDouble();
|
||||
} else {
|
||||
fractionalPart = numberValue.asDouble();
|
||||
}
|
||||
}
|
||||
|
@ -193,17 +181,16 @@ void Parser::parseNumber () {
|
|||
scanDigits(exponent);
|
||||
if (negative) {
|
||||
fractionalPart *= pow(10, -exponent.asDouble());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
fractionalPart *= pow(10, exponent.asDouble());
|
||||
}
|
||||
if (std::isnan(fractionalPart) || ! std::isfinite(fractionalPart)) {
|
||||
if (std::isnan(fractionalPart) || !std::isfinite(fractionalPart)) {
|
||||
throw Exception(Exception::NumberOutOfRange);
|
||||
}
|
||||
_b.addDouble(fractionalPart);
|
||||
}
|
||||
|
||||
void Parser::parseString () {
|
||||
void Parser::parseString() {
|
||||
// When we get here, we have seen a " character and now want to
|
||||
// find the end of the string and parse the string value to its
|
||||
// VPack representation. We assume that the string is short and
|
||||
|
@ -212,7 +199,7 @@ void Parser::parseString () {
|
|||
|
||||
ValueLength const base = _b._pos;
|
||||
_b.reserveSpace(1);
|
||||
_b._start[_b._pos++] = 0x40; // correct this later
|
||||
_b._start[_b._pos++] = 0x40; // correct this later
|
||||
|
||||
bool large = false; // set to true when we reach 128 bytes
|
||||
uint32_t highSurrogate = 0; // non-zero if high-surrogate was seen
|
||||
|
@ -225,30 +212,27 @@ void Parser::parseString () {
|
|||
if (options->validateUtf8Strings) {
|
||||
count = JSONStringCopyCheckUtf8(_b._start + _b._pos, _start + _pos,
|
||||
remainder);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
count = JSONStringCopy(_b._start + _b._pos, _start + _pos, remainder);
|
||||
}
|
||||
_pos += count;
|
||||
_b._pos += count;
|
||||
}
|
||||
int i = getOneOrThrow("Unfinished string");
|
||||
if (! large && _b._pos - (base + 1) > 126) {
|
||||
if (!large && _b._pos - (base + 1) > 126) {
|
||||
large = true;
|
||||
_b.reserveSpace(8);
|
||||
memmove(_b._start + base + 9, _b._start + base + 1,
|
||||
_b._pos - (base + 1));
|
||||
memmove(_b._start + base + 9, _b._start + base + 1, _b._pos - (base + 1));
|
||||
_b._pos += 8;
|
||||
}
|
||||
switch (i) {
|
||||
case '"':
|
||||
ValueLength len;
|
||||
if (! large) {
|
||||
if (!large) {
|
||||
len = _b._pos - (base + 1);
|
||||
_b._start[base] = 0x40 + static_cast<uint8_t>(len);
|
||||
// String is ready
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
len = _b._pos - (base + 9);
|
||||
_b._start[base] = 0xbf;
|
||||
for (ValueLength i = 1; i <= 8; i++) {
|
||||
|
@ -301,37 +285,32 @@ void Parser::parseString () {
|
|||
for (int j = 0; j < 4; j++) {
|
||||
i = consume();
|
||||
if (i < 0) {
|
||||
throw Exception(Exception::ParseError, "Unfinished \\uXXXX escape sequence");
|
||||
throw Exception(Exception::ParseError,
|
||||
"Unfinished \\uXXXX escape sequence");
|
||||
}
|
||||
if (i >= '0' && i <= '9') {
|
||||
v = (v << 4) + i - '0';
|
||||
}
|
||||
else if (i >= 'a' && i <= 'f') {
|
||||
} else if (i >= 'a' && i <= 'f') {
|
||||
v = (v << 4) + i - 'a' + 10;
|
||||
}
|
||||
else if (i >= 'A' && i <= 'F') {
|
||||
} else if (i >= 'A' && i <= 'F') {
|
||||
v = (v << 4) + i - 'A' + 10;
|
||||
}
|
||||
else {
|
||||
throw Exception(Exception::ParseError, "Illegal \\uXXXX escape sequence");
|
||||
} else {
|
||||
throw Exception(Exception::ParseError,
|
||||
"Illegal \\uXXXX escape sequence");
|
||||
}
|
||||
}
|
||||
if (v < 0x80) {
|
||||
_b.reserveSpace(1);
|
||||
_b._start[_b._pos++] = static_cast<uint8_t>(v);
|
||||
highSurrogate = 0;
|
||||
}
|
||||
else if (v < 0x800) {
|
||||
} else if (v < 0x800) {
|
||||
_b.reserveSpace(2);
|
||||
_b._start[_b._pos++] = 0xc0 + (v >> 6);
|
||||
_b._start[_b._pos++] = 0x80 + (v & 0x3f);
|
||||
highSurrogate = 0;
|
||||
}
|
||||
else if (v >= 0xdc00 && v < 0xe000 &&
|
||||
highSurrogate != 0) {
|
||||
} else if (v >= 0xdc00 && v < 0xe000 && highSurrogate != 0) {
|
||||
// Low surrogate, put the two together:
|
||||
v = 0x10000 + ((highSurrogate - 0xd800) << 10)
|
||||
+ v - 0xdc00;
|
||||
v = 0x10000 + ((highSurrogate - 0xd800) << 10) + v - 0xdc00;
|
||||
_b._pos -= 3;
|
||||
_b.reserveSpace(4);
|
||||
_b._start[_b._pos++] = 0xf0 + (v >> 18);
|
||||
|
@ -339,13 +318,11 @@ void Parser::parseString () {
|
|||
_b._start[_b._pos++] = 0x80 + ((v >> 6) & 0x3f);
|
||||
_b._start[_b._pos++] = 0x80 + (v & 0x3f);
|
||||
highSurrogate = 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (v >= 0xd800 && v < 0xdc00) {
|
||||
// High surrogate:
|
||||
highSurrogate = v;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
highSurrogate = 0;
|
||||
}
|
||||
_b.reserveSpace(3);
|
||||
|
@ -369,32 +346,26 @@ void Parser::parseString () {
|
|||
highSurrogate = 0;
|
||||
_b.reserveSpace(1);
|
||||
_b._start[_b._pos++] = static_cast<uint8_t>(i);
|
||||
}
|
||||
else {
|
||||
if (! options->validateUtf8Strings) {
|
||||
} else {
|
||||
if (!options->validateUtf8Strings) {
|
||||
highSurrogate = 0;
|
||||
_b.reserveSpace(1);
|
||||
_b._start[_b._pos++] = static_cast<uint8_t>(i);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// multi-byte UTF-8 sequence!
|
||||
int follow = 0;
|
||||
if ((i & 0xe0) == 0x80) {
|
||||
throw Exception(Exception::InvalidUtf8Sequence);
|
||||
}
|
||||
else if ((i & 0xe0) == 0xc0) {
|
||||
} else if ((i & 0xe0) == 0xc0) {
|
||||
// two-byte sequence
|
||||
follow = 1;
|
||||
}
|
||||
else if ((i & 0xf0) == 0xe0) {
|
||||
} else if ((i & 0xf0) == 0xe0) {
|
||||
// three-byte sequence
|
||||
follow = 2;
|
||||
}
|
||||
else if ((i & 0xf8) == 0xf0) {
|
||||
} else if ((i & 0xf8) == 0xf0) {
|
||||
// four-byte sequence
|
||||
follow = 3;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw Exception(Exception::InvalidUtf8Sequence);
|
||||
}
|
||||
|
||||
|
@ -416,14 +387,14 @@ void Parser::parseString () {
|
|||
}
|
||||
}
|
||||
|
||||
void Parser::parseArray () {
|
||||
void Parser::parseArray() {
|
||||
ValueLength base = _b._pos;
|
||||
_b.addArray();
|
||||
|
||||
int i = skipWhiteSpace("Expecting item or ']'");
|
||||
if (i == ']') {
|
||||
// empty array
|
||||
++_pos; // the closing ']'
|
||||
++_pos; // the closing ']'
|
||||
_b.close();
|
||||
return;
|
||||
}
|
||||
|
@ -452,16 +423,16 @@ void Parser::parseArray () {
|
|||
// should never get here
|
||||
VELOCYPACK_ASSERT(false);
|
||||
}
|
||||
|
||||
void Parser::parseObject () {
|
||||
|
||||
void Parser::parseObject() {
|
||||
ValueLength base = _b._pos;
|
||||
_b.addObject();
|
||||
|
||||
int i = skipWhiteSpace("Expecting item or '}'");
|
||||
if (i == '}') {
|
||||
// empty object
|
||||
consume(); // the closing ']'
|
||||
if (_nesting != 0 || ! options->keepTopLevelOpen) {
|
||||
consume(); // the closing ']'
|
||||
if (_nesting != 0 || !options->keepTopLevelOpen) {
|
||||
// only close if we've not been asked to keep top level open
|
||||
_b.close();
|
||||
}
|
||||
|
@ -483,26 +454,28 @@ void Parser::parseObject () {
|
|||
auto const lastPos = _b._pos;
|
||||
if (options->attributeExcludeHandler == nullptr) {
|
||||
parseString();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
parseString();
|
||||
if (options->attributeExcludeHandler->shouldExclude(Slice(_b._start + lastPos, options), _nesting)) {
|
||||
if (options->attributeExcludeHandler->shouldExclude(
|
||||
Slice(_b._start + lastPos, options), _nesting)) {
|
||||
excludeAttribute = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (! excludeAttribute && options->attributeTranslator != nullptr) {
|
||||
if (!excludeAttribute && options->attributeTranslator != nullptr) {
|
||||
// check if a translation for the attribute name exists
|
||||
Slice key(_b._start + lastPos, options);
|
||||
|
||||
if (key.isString()) {
|
||||
ValueLength keyLength;
|
||||
char const* p = key.getString(keyLength);
|
||||
uint8_t const* translated = options->attributeTranslator->translate(p, keyLength);
|
||||
uint8_t const* translated =
|
||||
options->attributeTranslator->translate(p, keyLength);
|
||||
|
||||
if (translated != nullptr) {
|
||||
// found translation... now reset position to old key position
|
||||
// and simply overwrite the existing key with the numeric translation id
|
||||
// and simply overwrite the existing key with the numeric translation
|
||||
// id
|
||||
_b._pos = lastPos;
|
||||
_b.addUInt(Slice(translated, options).getUInt());
|
||||
}
|
||||
|
@ -514,7 +487,7 @@ void Parser::parseObject () {
|
|||
if (i != ':') {
|
||||
throw Exception(Exception::ParseError, "Expecting ':'");
|
||||
}
|
||||
++_pos; // skip over the colon
|
||||
++_pos; // skip over the colon
|
||||
|
||||
parseJson();
|
||||
|
||||
|
@ -526,7 +499,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();
|
||||
}
|
||||
|
@ -535,40 +508,40 @@ void Parser::parseObject () {
|
|||
}
|
||||
if (i != ',') {
|
||||
throw Exception(Exception::ParseError, "Expecting ',' or '}'");
|
||||
}
|
||||
}
|
||||
// skip over ','
|
||||
++_pos; // the ','
|
||||
i = skipWhiteSpace("Expecting '\"' or '}'");
|
||||
}
|
||||
|
||||
|
||||
// should never get here
|
||||
VELOCYPACK_ASSERT(false);
|
||||
}
|
||||
|
||||
void Parser::parseJson () {
|
||||
|
||||
void Parser::parseJson() {
|
||||
skipWhiteSpace("Expecting item");
|
||||
|
||||
int i = consume();
|
||||
if (i < 0) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
switch (i) {
|
||||
case '{':
|
||||
case '{':
|
||||
parseObject(); // this consumes the closing '}' or throws
|
||||
break;
|
||||
case '[':
|
||||
parseArray(); // this consumes the closing ']' or throws
|
||||
parseArray(); // this consumes the closing ']' or throws
|
||||
break;
|
||||
case 't':
|
||||
parseTrue(); // this consumes "rue" or throws
|
||||
parseTrue(); // this consumes "rue" or throws
|
||||
break;
|
||||
case 'f':
|
||||
parseFalse(); // this consumes "alse" or throws
|
||||
parseFalse(); // this consumes "alse" or throws
|
||||
break;
|
||||
case 'n':
|
||||
parseNull(); // this consumes "ull" or throws
|
||||
parseNull(); // this consumes "ull" or throws
|
||||
break;
|
||||
case '"':
|
||||
case '"':
|
||||
parseString();
|
||||
break;
|
||||
default: {
|
||||
|
@ -581,4 +554,3 @@ void Parser::parseJson () {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,122 +37,183 @@
|
|||
|
||||
using namespace arangodb::velocypack;
|
||||
using VT = arangodb::velocypack::ValueType;
|
||||
|
||||
VT const Slice::TypeMap[256] = {
|
||||
/* 0x00 */ VT::None, /* 0x01 */ VT::Array, /* 0x02 */ VT::Array, /* 0x03 */ VT::Array,
|
||||
/* 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::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,
|
||||
/* 0x24 */ VT::Int, /* 0x25 */ VT::Int, /* 0x26 */ VT::Int, /* 0x27 */ VT::Int,
|
||||
/* 0x28 */ VT::UInt, /* 0x29 */ VT::UInt, /* 0x2a */ VT::UInt, /* 0x2b */ VT::UInt,
|
||||
/* 0x2c */ VT::UInt, /* 0x2d */ VT::UInt, /* 0x2e */ VT::UInt, /* 0x2f */ VT::UInt,
|
||||
/* 0x30 */ VT::SmallInt, /* 0x31 */ VT::SmallInt, /* 0x32 */ VT::SmallInt, /* 0x33 */ VT::SmallInt,
|
||||
/* 0x34 */ VT::SmallInt, /* 0x35 */ VT::SmallInt, /* 0x36 */ VT::SmallInt, /* 0x37 */ VT::SmallInt,
|
||||
/* 0x38 */ VT::SmallInt, /* 0x39 */ VT::SmallInt, /* 0x3a */ VT::SmallInt, /* 0x3b */ VT::SmallInt,
|
||||
/* 0x3c */ VT::SmallInt, /* 0x3d */ VT::SmallInt, /* 0x3e */ VT::SmallInt, /* 0x3f */ VT::SmallInt,
|
||||
/* 0x40 */ VT::String, /* 0x41 */ VT::String, /* 0x42 */ VT::String, /* 0x43 */ VT::String,
|
||||
/* 0x44 */ VT::String, /* 0x45 */ VT::String, /* 0x46 */ VT::String, /* 0x47 */ VT::String,
|
||||
/* 0x48 */ VT::String, /* 0x49 */ VT::String, /* 0x4a */ VT::String, /* 0x4b */ VT::String,
|
||||
/* 0x4c */ VT::String, /* 0x4d */ VT::String, /* 0x4e */ VT::String, /* 0x4f */ VT::String,
|
||||
/* 0x50 */ VT::String, /* 0x51 */ VT::String, /* 0x52 */ VT::String, /* 0x53 */ VT::String,
|
||||
/* 0x54 */ VT::String, /* 0x55 */ VT::String, /* 0x56 */ VT::String, /* 0x57 */ VT::String,
|
||||
/* 0x58 */ VT::String, /* 0x59 */ VT::String, /* 0x5a */ VT::String, /* 0x5b */ VT::String,
|
||||
/* 0x5c */ VT::String, /* 0x5d */ VT::String, /* 0x5e */ VT::String, /* 0x5f */ VT::String,
|
||||
/* 0x60 */ VT::String, /* 0x61 */ VT::String, /* 0x62 */ VT::String, /* 0x63 */ VT::String,
|
||||
/* 0x64 */ VT::String, /* 0x65 */ VT::String, /* 0x66 */ VT::String, /* 0x67 */ VT::String,
|
||||
/* 0x68 */ VT::String, /* 0x69 */ VT::String, /* 0x6a */ VT::String, /* 0x6b */ VT::String,
|
||||
/* 0x6c */ VT::String, /* 0x6d */ VT::String, /* 0x6e */ VT::String, /* 0x6f */ VT::String,
|
||||
/* 0x70 */ VT::String, /* 0x71 */ VT::String, /* 0x72 */ VT::String, /* 0x73 */ VT::String,
|
||||
/* 0x74 */ VT::String, /* 0x75 */ VT::String, /* 0x76 */ VT::String, /* 0x77 */ VT::String,
|
||||
/* 0x78 */ VT::String, /* 0x79 */ VT::String, /* 0x7a */ VT::String, /* 0x7b */ VT::String,
|
||||
/* 0x7c */ VT::String, /* 0x7d */ VT::String, /* 0x7e */ VT::String, /* 0x7f */ VT::String,
|
||||
/* 0x80 */ VT::String, /* 0x81 */ VT::String, /* 0x82 */ VT::String, /* 0x83 */ VT::String,
|
||||
/* 0x84 */ VT::String, /* 0x85 */ VT::String, /* 0x86 */ VT::String, /* 0x87 */ VT::String,
|
||||
/* 0x88 */ VT::String, /* 0x89 */ VT::String, /* 0x8a */ VT::String, /* 0x8b */ VT::String,
|
||||
/* 0x8c */ VT::String, /* 0x8d */ VT::String, /* 0x8e */ VT::String, /* 0x8f */ VT::String,
|
||||
/* 0x90 */ VT::String, /* 0x91 */ VT::String, /* 0x92 */ VT::String, /* 0x93 */ VT::String,
|
||||
/* 0x94 */ VT::String, /* 0x95 */ VT::String, /* 0x96 */ VT::String, /* 0x97 */ VT::String,
|
||||
/* 0x98 */ VT::String, /* 0x99 */ VT::String, /* 0x9a */ VT::String, /* 0x9b */ VT::String,
|
||||
/* 0x9c */ VT::String, /* 0x9d */ VT::String, /* 0x9e */ VT::String, /* 0x9f */ VT::String,
|
||||
/* 0xa0 */ VT::String, /* 0xa1 */ VT::String, /* 0xa2 */ VT::String, /* 0xa3 */ VT::String,
|
||||
/* 0xa4 */ VT::String, /* 0xa5 */ VT::String, /* 0xa6 */ VT::String, /* 0xa7 */ VT::String,
|
||||
/* 0xa8 */ VT::String, /* 0xa9 */ VT::String, /* 0xaa */ VT::String, /* 0xab */ VT::String,
|
||||
/* 0xac */ VT::String, /* 0xad */ VT::String, /* 0xae */ VT::String, /* 0xaf */ VT::String,
|
||||
/* 0xb0 */ VT::String, /* 0xb1 */ VT::String, /* 0xb2 */ VT::String, /* 0xb3 */ VT::String,
|
||||
/* 0xb4 */ VT::String, /* 0xb5 */ VT::String, /* 0xb6 */ VT::String, /* 0xb7 */ VT::String,
|
||||
/* 0xb8 */ VT::String, /* 0xb9 */ VT::String, /* 0xba */ VT::String, /* 0xbb */ VT::String,
|
||||
/* 0xbc */ VT::String, /* 0xbd */ VT::String, /* 0xbe */ VT::String, /* 0xbf */ VT::String,
|
||||
/* 0xc0 */ VT::Binary, /* 0xc1 */ VT::Binary, /* 0xc2 */ VT::Binary, /* 0xc3 */ VT::Binary,
|
||||
/* 0xc4 */ VT::Binary, /* 0xc5 */ VT::Binary, /* 0xc6 */ VT::Binary, /* 0xc7 */ VT::Binary,
|
||||
/* 0xc8 */ VT::BCD, /* 0xc9 */ VT::BCD, /* 0xca */ VT::BCD, /* 0xcb */ VT::BCD,
|
||||
/* 0xcc */ VT::BCD, /* 0xcd */ VT::BCD, /* 0xce */ VT::BCD, /* 0xcf */ VT::BCD,
|
||||
/* 0xd0 */ VT::BCD, /* 0xd1 */ VT::BCD, /* 0xd2 */ VT::BCD, /* 0xd3 */ VT::BCD,
|
||||
/* 0xd4 */ VT::BCD, /* 0xd5 */ VT::BCD, /* 0xd6 */ VT::BCD, /* 0xd7 */ VT::BCD,
|
||||
/* 0xd8 */ VT::None, /* 0xd9 */ VT::None, /* 0xda */ VT::None, /* 0xdb */ VT::None,
|
||||
/* 0xdc */ VT::None, /* 0xdd */ VT::None, /* 0xde */ VT::None, /* 0xdf */ VT::None,
|
||||
/* 0xe0 */ VT::None, /* 0xe1 */ VT::None, /* 0xe2 */ VT::None, /* 0xe3 */ VT::None,
|
||||
/* 0xe4 */ VT::None, /* 0xe5 */ VT::None, /* 0xe6 */ VT::None, /* 0xe7 */ VT::None,
|
||||
/* 0xe8 */ VT::None, /* 0xe9 */ VT::None, /* 0xea */ VT::None, /* 0xeb */ VT::None,
|
||||
/* 0xec */ VT::None, /* 0xed */ VT::None, /* 0xee */ VT::None, /* 0xef */ VT::None,
|
||||
/* 0xf0 */ VT::Custom, /* 0xf1 */ VT::Custom, /* 0xf2 */ VT::Custom, /* 0xf3 */ VT::Custom,
|
||||
/* 0xf4 */ VT::Custom, /* 0xf5 */ VT::Custom, /* 0xf6 */ VT::Custom, /* 0xf7 */ VT::Custom,
|
||||
/* 0xf8 */ VT::Custom, /* 0xf9 */ VT::Custom, /* 0xfa */ VT::Custom, /* 0xfb */ VT::Custom,
|
||||
/* 0xfc */ VT::Custom, /* 0xfd */ VT::Custom, /* 0xfe */ VT::Custom, /* 0xff */ VT::Custom
|
||||
};
|
||||
|
||||
unsigned int const Slice::WidthMap[32] = {
|
||||
0, // 0x00, None
|
||||
1, // 0x01, empty array
|
||||
1, // 0x02, array without index table
|
||||
2, // 0x03, array without index table
|
||||
4, // 0x04, array without index table
|
||||
8, // 0x05, array without index table
|
||||
1, // 0x06, array with index table
|
||||
2, // 0x07, array with index table
|
||||
4, // 0x08, array with index table
|
||||
8, // 0x09, array with index table
|
||||
1, // 0x0a, empty object
|
||||
1, // 0x0b, object with sorted index table
|
||||
2, // 0x0c, object with sorted index table
|
||||
4, // 0x0d, object with sorted index table
|
||||
8, // 0x0e, object with sorted index table
|
||||
1, // 0x0f, object with unsorted index table
|
||||
2, // 0x10, object with unsorted index table
|
||||
4, // 0x11, object with unsorted index table
|
||||
8, // 0x12, object with unsorted index table
|
||||
0
|
||||
};
|
||||
|
||||
unsigned int const Slice::FirstSubMap[32] = {
|
||||
0, // 0x00, None
|
||||
1, // 0x01, empty array
|
||||
2, // 0x02, array without index table
|
||||
3, // 0x03, array without index table
|
||||
5, // 0x04, array without index table
|
||||
9, // 0x05, array without index table
|
||||
3, // 0x06, array with index table
|
||||
5, // 0x07, array with index table
|
||||
8, // 0x08, array with index table
|
||||
8, // 0x09, array with index table
|
||||
1, // 0x0a, empty object
|
||||
3, // 0x0b, object with sorted index table
|
||||
5, // 0x0c, object with sorted index table
|
||||
8, // 0x0d, object with sorted index table
|
||||
8, // 0x0e, object with sorted index table
|
||||
3, // 0x0f, object with unsorted index table
|
||||
5, // 0x10, object with unsorted index table
|
||||
8, // 0x11, object with unsorted index table
|
||||
8, // 0x12, object with unsorted index table
|
||||
0
|
||||
};
|
||||
VT const Slice::TypeMap[256] = {
|
||||
/* 0x00 */ VT::None, /* 0x01 */ VT::Array,
|
||||
/* 0x02 */ VT::Array, /* 0x03 */ VT::Array,
|
||||
/* 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::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,
|
||||
/* 0x24 */ VT::Int, /* 0x25 */ VT::Int,
|
||||
/* 0x26 */ VT::Int, /* 0x27 */ VT::Int,
|
||||
/* 0x28 */ VT::UInt, /* 0x29 */ VT::UInt,
|
||||
/* 0x2a */ VT::UInt, /* 0x2b */ VT::UInt,
|
||||
/* 0x2c */ VT::UInt, /* 0x2d */ VT::UInt,
|
||||
/* 0x2e */ VT::UInt, /* 0x2f */ VT::UInt,
|
||||
/* 0x30 */ VT::SmallInt, /* 0x31 */ VT::SmallInt,
|
||||
/* 0x32 */ VT::SmallInt, /* 0x33 */ VT::SmallInt,
|
||||
/* 0x34 */ VT::SmallInt, /* 0x35 */ VT::SmallInt,
|
||||
/* 0x36 */ VT::SmallInt, /* 0x37 */ VT::SmallInt,
|
||||
/* 0x38 */ VT::SmallInt, /* 0x39 */ VT::SmallInt,
|
||||
/* 0x3a */ VT::SmallInt, /* 0x3b */ VT::SmallInt,
|
||||
/* 0x3c */ VT::SmallInt, /* 0x3d */ VT::SmallInt,
|
||||
/* 0x3e */ VT::SmallInt, /* 0x3f */ VT::SmallInt,
|
||||
/* 0x40 */ VT::String, /* 0x41 */ VT::String,
|
||||
/* 0x42 */ VT::String, /* 0x43 */ VT::String,
|
||||
/* 0x44 */ VT::String, /* 0x45 */ VT::String,
|
||||
/* 0x46 */ VT::String, /* 0x47 */ VT::String,
|
||||
/* 0x48 */ VT::String, /* 0x49 */ VT::String,
|
||||
/* 0x4a */ VT::String, /* 0x4b */ VT::String,
|
||||
/* 0x4c */ VT::String, /* 0x4d */ VT::String,
|
||||
/* 0x4e */ VT::String, /* 0x4f */ VT::String,
|
||||
/* 0x50 */ VT::String, /* 0x51 */ VT::String,
|
||||
/* 0x52 */ VT::String, /* 0x53 */ VT::String,
|
||||
/* 0x54 */ VT::String, /* 0x55 */ VT::String,
|
||||
/* 0x56 */ VT::String, /* 0x57 */ VT::String,
|
||||
/* 0x58 */ VT::String, /* 0x59 */ VT::String,
|
||||
/* 0x5a */ VT::String, /* 0x5b */ VT::String,
|
||||
/* 0x5c */ VT::String, /* 0x5d */ VT::String,
|
||||
/* 0x5e */ VT::String, /* 0x5f */ VT::String,
|
||||
/* 0x60 */ VT::String, /* 0x61 */ VT::String,
|
||||
/* 0x62 */ VT::String, /* 0x63 */ VT::String,
|
||||
/* 0x64 */ VT::String, /* 0x65 */ VT::String,
|
||||
/* 0x66 */ VT::String, /* 0x67 */ VT::String,
|
||||
/* 0x68 */ VT::String, /* 0x69 */ VT::String,
|
||||
/* 0x6a */ VT::String, /* 0x6b */ VT::String,
|
||||
/* 0x6c */ VT::String, /* 0x6d */ VT::String,
|
||||
/* 0x6e */ VT::String, /* 0x6f */ VT::String,
|
||||
/* 0x70 */ VT::String, /* 0x71 */ VT::String,
|
||||
/* 0x72 */ VT::String, /* 0x73 */ VT::String,
|
||||
/* 0x74 */ VT::String, /* 0x75 */ VT::String,
|
||||
/* 0x76 */ VT::String, /* 0x77 */ VT::String,
|
||||
/* 0x78 */ VT::String, /* 0x79 */ VT::String,
|
||||
/* 0x7a */ VT::String, /* 0x7b */ VT::String,
|
||||
/* 0x7c */ VT::String, /* 0x7d */ VT::String,
|
||||
/* 0x7e */ VT::String, /* 0x7f */ VT::String,
|
||||
/* 0x80 */ VT::String, /* 0x81 */ VT::String,
|
||||
/* 0x82 */ VT::String, /* 0x83 */ VT::String,
|
||||
/* 0x84 */ VT::String, /* 0x85 */ VT::String,
|
||||
/* 0x86 */ VT::String, /* 0x87 */ VT::String,
|
||||
/* 0x88 */ VT::String, /* 0x89 */ VT::String,
|
||||
/* 0x8a */ VT::String, /* 0x8b */ VT::String,
|
||||
/* 0x8c */ VT::String, /* 0x8d */ VT::String,
|
||||
/* 0x8e */ VT::String, /* 0x8f */ VT::String,
|
||||
/* 0x90 */ VT::String, /* 0x91 */ VT::String,
|
||||
/* 0x92 */ VT::String, /* 0x93 */ VT::String,
|
||||
/* 0x94 */ VT::String, /* 0x95 */ VT::String,
|
||||
/* 0x96 */ VT::String, /* 0x97 */ VT::String,
|
||||
/* 0x98 */ VT::String, /* 0x99 */ VT::String,
|
||||
/* 0x9a */ VT::String, /* 0x9b */ VT::String,
|
||||
/* 0x9c */ VT::String, /* 0x9d */ VT::String,
|
||||
/* 0x9e */ VT::String, /* 0x9f */ VT::String,
|
||||
/* 0xa0 */ VT::String, /* 0xa1 */ VT::String,
|
||||
/* 0xa2 */ VT::String, /* 0xa3 */ VT::String,
|
||||
/* 0xa4 */ VT::String, /* 0xa5 */ VT::String,
|
||||
/* 0xa6 */ VT::String, /* 0xa7 */ VT::String,
|
||||
/* 0xa8 */ VT::String, /* 0xa9 */ VT::String,
|
||||
/* 0xaa */ VT::String, /* 0xab */ VT::String,
|
||||
/* 0xac */ VT::String, /* 0xad */ VT::String,
|
||||
/* 0xae */ VT::String, /* 0xaf */ VT::String,
|
||||
/* 0xb0 */ VT::String, /* 0xb1 */ VT::String,
|
||||
/* 0xb2 */ VT::String, /* 0xb3 */ VT::String,
|
||||
/* 0xb4 */ VT::String, /* 0xb5 */ VT::String,
|
||||
/* 0xb6 */ VT::String, /* 0xb7 */ VT::String,
|
||||
/* 0xb8 */ VT::String, /* 0xb9 */ VT::String,
|
||||
/* 0xba */ VT::String, /* 0xbb */ VT::String,
|
||||
/* 0xbc */ VT::String, /* 0xbd */ VT::String,
|
||||
/* 0xbe */ VT::String, /* 0xbf */ VT::String,
|
||||
/* 0xc0 */ VT::Binary, /* 0xc1 */ VT::Binary,
|
||||
/* 0xc2 */ VT::Binary, /* 0xc3 */ VT::Binary,
|
||||
/* 0xc4 */ VT::Binary, /* 0xc5 */ VT::Binary,
|
||||
/* 0xc6 */ VT::Binary, /* 0xc7 */ VT::Binary,
|
||||
/* 0xc8 */ VT::BCD, /* 0xc9 */ VT::BCD,
|
||||
/* 0xca */ VT::BCD, /* 0xcb */ VT::BCD,
|
||||
/* 0xcc */ VT::BCD, /* 0xcd */ VT::BCD,
|
||||
/* 0xce */ VT::BCD, /* 0xcf */ VT::BCD,
|
||||
/* 0xd0 */ VT::BCD, /* 0xd1 */ VT::BCD,
|
||||
/* 0xd2 */ VT::BCD, /* 0xd3 */ VT::BCD,
|
||||
/* 0xd4 */ VT::BCD, /* 0xd5 */ VT::BCD,
|
||||
/* 0xd6 */ VT::BCD, /* 0xd7 */ VT::BCD,
|
||||
/* 0xd8 */ VT::None, /* 0xd9 */ VT::None,
|
||||
/* 0xda */ VT::None, /* 0xdb */ VT::None,
|
||||
/* 0xdc */ VT::None, /* 0xdd */ VT::None,
|
||||
/* 0xde */ VT::None, /* 0xdf */ VT::None,
|
||||
/* 0xe0 */ VT::None, /* 0xe1 */ VT::None,
|
||||
/* 0xe2 */ VT::None, /* 0xe3 */ VT::None,
|
||||
/* 0xe4 */ VT::None, /* 0xe5 */ VT::None,
|
||||
/* 0xe6 */ VT::None, /* 0xe7 */ VT::None,
|
||||
/* 0xe8 */ VT::None, /* 0xe9 */ VT::None,
|
||||
/* 0xea */ VT::None, /* 0xeb */ VT::None,
|
||||
/* 0xec */ VT::None, /* 0xed */ VT::None,
|
||||
/* 0xee */ VT::None, /* 0xef */ VT::None,
|
||||
/* 0xf0 */ VT::Custom, /* 0xf1 */ VT::Custom,
|
||||
/* 0xf2 */ VT::Custom, /* 0xf3 */ VT::Custom,
|
||||
/* 0xf4 */ VT::Custom, /* 0xf5 */ VT::Custom,
|
||||
/* 0xf6 */ VT::Custom, /* 0xf7 */ VT::Custom,
|
||||
/* 0xf8 */ VT::Custom, /* 0xf9 */ VT::Custom,
|
||||
/* 0xfa */ VT::Custom, /* 0xfb */ VT::Custom,
|
||||
/* 0xfc */ VT::Custom, /* 0xfd */ VT::Custom,
|
||||
/* 0xfe */ VT::Custom, /* 0xff */ VT::Custom};
|
||||
|
||||
unsigned int const Slice::WidthMap[32] = {
|
||||
0, // 0x00, None
|
||||
1, // 0x01, empty array
|
||||
1, // 0x02, array without index table
|
||||
2, // 0x03, array without index table
|
||||
4, // 0x04, array without index table
|
||||
8, // 0x05, array without index table
|
||||
1, // 0x06, array with index table
|
||||
2, // 0x07, array with index table
|
||||
4, // 0x08, array with index table
|
||||
8, // 0x09, array with index table
|
||||
1, // 0x0a, empty object
|
||||
1, // 0x0b, object with sorted index table
|
||||
2, // 0x0c, object with sorted index table
|
||||
4, // 0x0d, object with sorted index table
|
||||
8, // 0x0e, object with sorted index table
|
||||
1, // 0x0f, object with unsorted index table
|
||||
2, // 0x10, object with unsorted index table
|
||||
4, // 0x11, object with unsorted index table
|
||||
8, // 0x12, object with unsorted index table
|
||||
0};
|
||||
|
||||
unsigned int const Slice::FirstSubMap[32] = {
|
||||
0, // 0x00, None
|
||||
1, // 0x01, empty array
|
||||
2, // 0x02, array without index table
|
||||
3, // 0x03, array without index table
|
||||
5, // 0x04, array without index table
|
||||
9, // 0x05, array without index table
|
||||
3, // 0x06, array with index table
|
||||
5, // 0x07, array with index table
|
||||
8, // 0x08, array with index table
|
||||
8, // 0x09, array with index table
|
||||
1, // 0x0a, empty object
|
||||
3, // 0x0b, object with sorted index table
|
||||
5, // 0x0c, object with sorted index table
|
||||
8, // 0x0d, object with sorted index table
|
||||
8, // 0x0e, object with sorted index table
|
||||
3, // 0x0f, object with unsorted index table
|
||||
5, // 0x10, object with unsorted index table
|
||||
8, // 0x11, object with unsorted index table
|
||||
8, // 0x12, object with unsorted index table
|
||||
0};
|
||||
|
||||
// translates an integer key into a string
|
||||
Slice Slice::translate () const {
|
||||
Slice Slice::translate() const {
|
||||
VELOCYPACK_ASSERT(isSmallInt() || isUInt());
|
||||
uint64_t id = getUInt();
|
||||
|
||||
|
@ -163,15 +224,15 @@ Slice Slice::translate () const {
|
|||
return Slice(options->attributeTranslator->translate(id), options);
|
||||
}
|
||||
|
||||
std::string Slice::toJson () const {
|
||||
std::string Slice::toJson() const {
|
||||
std::string buffer;
|
||||
StringSink sink(&buffer);
|
||||
Dumper dumper(&sink, options);
|
||||
dumper.dump(this);
|
||||
return std::move(buffer);
|
||||
}
|
||||
|
||||
std::string Slice::toString () const {
|
||||
|
||||
std::string Slice::toString() const {
|
||||
// copy options and set prettyPrint in copy
|
||||
Options prettyOptions = *options;
|
||||
prettyOptions.prettyPrint = true;
|
||||
|
@ -182,14 +243,12 @@ std::string Slice::toString () const {
|
|||
return std::move(buffer);
|
||||
}
|
||||
|
||||
std::string Slice::hexType () const {
|
||||
return std::move(HexDump::toHex(head()));
|
||||
}
|
||||
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)) {
|
||||
Slice Slice::get(std::string const& attribute) const {
|
||||
if (!isType(ValueType::Object)) {
|
||||
throw Exception(Exception::InvalidValueType, "Expecting Object");
|
||||
}
|
||||
|
||||
|
@ -203,25 +262,19 @@ Slice Slice::get (std::string const& attribute) const {
|
|||
// 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) {
|
||||
if (offsetSize < 8) {
|
||||
n = readInteger<ValueLength>(_start + 1 + offsetSize, offsetSize);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
n = readInteger<ValueLength>(_start + end - offsetSize, offsetSize);
|
||||
}
|
||||
|
||||
|
||||
if (n == 1) {
|
||||
// Just one attribute, there is no index table!
|
||||
if (dataOffset == 0) {
|
||||
|
@ -230,18 +283,16 @@ Slice Slice::get (std::string const& attribute) const {
|
|||
|
||||
Slice key = Slice(_start + dataOffset, options);
|
||||
|
||||
if (key.isString()) {
|
||||
if (! key.isEqualString(attribute)) {
|
||||
if (key.isString()) {
|
||||
if (!key.isEqualString(attribute)) {
|
||||
return Slice();
|
||||
}
|
||||
}
|
||||
else if (key.isInteger()) {
|
||||
} else if (key.isInteger()) {
|
||||
// translate key
|
||||
if (! key.translate().isEqualString(attribute)) {
|
||||
if (!key.translate().isEqualString(attribute)) {
|
||||
return Slice();
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// invalid key
|
||||
return Slice();
|
||||
}
|
||||
|
@ -249,8 +300,8 @@ Slice Slice::get (std::string const& attribute) const {
|
|||
return Slice(key.start() + key.byteSize(), options);
|
||||
}
|
||||
|
||||
ValueLength const ieBase = end - n * offsetSize
|
||||
- (offsetSize == 8 ? offsetSize : 0);
|
||||
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
|
||||
|
@ -266,22 +317,21 @@ Slice Slice::get (std::string const& attribute) const {
|
|||
}
|
||||
|
||||
// return the value for an Int object
|
||||
int64_t Slice::getInt () const {
|
||||
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 {
|
||||
} 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) {
|
||||
if (h >= 0x28 && h <= 0x2f) {
|
||||
// UInt
|
||||
uint64_t v = getUInt();
|
||||
if (v > static_cast<uint64_t>(INT64_MAX)) {
|
||||
|
@ -289,7 +339,7 @@ int64_t Slice::getInt () const {
|
|||
}
|
||||
return static_cast<int64_t>(v);
|
||||
}
|
||||
|
||||
|
||||
if (h >= 0x30 && h <= 0x3f) {
|
||||
// SmallInt
|
||||
return getSmallInt();
|
||||
|
@ -299,15 +349,15 @@ int64_t Slice::getInt () const {
|
|||
}
|
||||
|
||||
// return the value for a UInt object
|
||||
uint64_t Slice::getUInt () const {
|
||||
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
|
||||
// Int
|
||||
int64_t v = getInt();
|
||||
if (v < 0) {
|
||||
throw Exception(Exception::NumberOutOfRange);
|
||||
|
@ -324,12 +374,12 @@ uint64_t Slice::getUInt () const {
|
|||
// 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 {
|
||||
int64_t Slice::getSmallInt() const {
|
||||
uint8_t const h = head();
|
||||
|
||||
if (h >= 0x30 && h <= 0x39) {
|
||||
|
@ -342,50 +392,50 @@ int64_t Slice::getSmallInt () const {
|
|||
return static_cast<int64_t>(h - 0x3a) - 6;
|
||||
}
|
||||
|
||||
if ((h >= 0x20 && h <= 0x27) ||
|
||||
(h >= 0x28 && h <= 0x2f)) {
|
||||
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
|
||||
// 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 {
|
||||
int Slice::compareString(std::string const& attribute) const {
|
||||
ValueLength keyLength;
|
||||
char const* k = getString(keyLength);
|
||||
char const* k = getString(keyLength);
|
||||
size_t const attributeLength = attribute.size();
|
||||
size_t const compareLength = (std::min)(static_cast<size_t>(keyLength), attributeLength);
|
||||
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 (keyLength > attributeLength) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Slice::isEqualString (std::string const& attribute) const {
|
||||
bool Slice::isEqualString(std::string const& attribute) const {
|
||||
ValueLength keyLength;
|
||||
char const* k = getString(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 {
|
||||
Slice Slice::getFromCompactObject(std::string const& attribute) const {
|
||||
ObjectIterator it(*this);
|
||||
while (it.valid()) {
|
||||
Slice key = it.key();
|
||||
if (key.isString()) {
|
||||
if (key.isString()) {
|
||||
if (key.isEqualString(attribute)) {
|
||||
return Slice(key.start() + key.byteSize(), options);
|
||||
}
|
||||
}
|
||||
else if (key.isInteger()) {
|
||||
} else if (key.isInteger()) {
|
||||
if (key.translate().isEqualString(attribute)) {
|
||||
return Slice(key.start() + key.byteSize(), options);
|
||||
}
|
||||
|
@ -396,9 +446,9 @@ Slice Slice::getFromCompactObject (std::string const& attribute) const {
|
|||
// not found
|
||||
return Slice();
|
||||
}
|
||||
|
||||
|
||||
// get the offset for the nth member from an Array or Object type
|
||||
ValueLength Slice::getNthOffset (ValueLength index) const {
|
||||
ValueLength Slice::getNthOffset(ValueLength index) const {
|
||||
VELOCYPACK_ASSERT(type() == ValueType::Array || type() == ValueType::Object);
|
||||
|
||||
auto const h = head();
|
||||
|
@ -416,17 +466,15 @@ ValueLength Slice::getNthOffset (ValueLength index) const {
|
|||
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:
|
||||
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) {
|
||||
} else if (offsetSize < 8) {
|
||||
n = readInteger<ValueLength>(_start + 1 + offsetSize, offsetSize);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
n = readInteger<ValueLength>(_start + end - offsetSize, offsetSize);
|
||||
}
|
||||
|
||||
|
@ -446,14 +494,14 @@ ValueLength Slice::getNthOffset (ValueLength index) const {
|
|||
Slice firstItem(_start + dataOffset, options);
|
||||
return dataOffset + index * firstItem.byteSize();
|
||||
}
|
||||
|
||||
ValueLength const ieBase = end - n * offsetSize + index * offsetSize
|
||||
- (offsetSize == 8 ? 8 : 0);
|
||||
|
||||
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
|
||||
Slice Slice::getNth (ValueLength index) const {
|
||||
// extract the nth member from an Array
|
||||
Slice Slice::getNth(ValueLength index) const {
|
||||
VELOCYPACK_ASSERT(type() == ValueType::Array);
|
||||
|
||||
auto const h = head();
|
||||
|
@ -465,8 +513,8 @@ Slice Slice::getNth (ValueLength index) const {
|
|||
return Slice(_start + getNthOffset(index), options);
|
||||
}
|
||||
|
||||
// extract the nth member from an Object
|
||||
Slice Slice::getNthKey (ValueLength index, bool translate) const {
|
||||
// extract the nth member from an Object
|
||||
Slice Slice::getNthKey(ValueLength index, bool translate) const {
|
||||
VELOCYPACK_ASSERT(type() == ValueType::Object);
|
||||
|
||||
auto const h = head();
|
||||
|
@ -475,7 +523,7 @@ Slice Slice::getNthKey (ValueLength index, bool translate) const {
|
|||
throw Exception(Exception::IndexOutOfBounds);
|
||||
}
|
||||
|
||||
Slice s(_start + getNthOffset(index), options);
|
||||
Slice s(_start + getNthOffset(index), options);
|
||||
|
||||
if (translate) {
|
||||
return s.makeKey();
|
||||
|
@ -484,7 +532,7 @@ Slice Slice::getNthKey (ValueLength index, bool translate) const {
|
|||
return s;
|
||||
}
|
||||
|
||||
Slice Slice::makeKey () const {
|
||||
Slice Slice::makeKey() const {
|
||||
if (isString()) {
|
||||
return *this;
|
||||
}
|
||||
|
@ -494,9 +542,9 @@ Slice Slice::makeKey () const {
|
|||
|
||||
throw Exception(Exception::InternalError, "Cannot translate key");
|
||||
}
|
||||
|
||||
|
||||
// get the offset for the nth member from a compact Array or Object type
|
||||
ValueLength Slice::getNthOffsetFromCompact (ValueLength index) const {
|
||||
ValueLength Slice::getNthOffsetFromCompact(ValueLength index) const {
|
||||
ValueLength end = readVariableValueLength<false>(_start + 1);
|
||||
ValueLength n = readVariableValueLength<true>(_start + end - 1);
|
||||
if (index >= n) {
|
||||
|
@ -504,7 +552,7 @@ ValueLength Slice::getNthOffsetFromCompact (ValueLength index) const {
|
|||
}
|
||||
|
||||
auto const h = head();
|
||||
ValueLength offset = 1 + getVariableValueLength(end);
|
||||
ValueLength offset = 1 + getVariableValueLength(end);
|
||||
ValueLength current = 0;
|
||||
while (current != index) {
|
||||
uint8_t const* s = _start + offset;
|
||||
|
@ -520,26 +568,24 @@ ValueLength Slice::getNthOffsetFromCompact (ValueLength index) const {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
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);
|
||||
Slice key(_start + readInteger<ValueLength>(_start + offset, offsetSize),
|
||||
options);
|
||||
|
||||
if (key.isString()) {
|
||||
if (! key.isEqualString(attribute)) {
|
||||
if (!key.isEqualString(attribute)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (key.isInteger()) {
|
||||
} else if (key.isInteger()) {
|
||||
// translate key
|
||||
if (! key.translate().isEqualString(attribute)) {
|
||||
if (!key.translate().isEqualString(attribute)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// invalid key type
|
||||
return Slice();
|
||||
}
|
||||
|
@ -553,12 +599,11 @@ Slice Slice::searchObjectKeyLinear (std::string const& attribute,
|
|||
}
|
||||
|
||||
// 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 {
|
||||
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;
|
||||
|
||||
|
@ -567,17 +612,16 @@ Slice Slice::searchObjectKeyBinary (std::string const& attribute,
|
|||
ValueLength index = l + ((r - l) / 2);
|
||||
|
||||
ValueLength offset = ieBase + index * offsetSize;
|
||||
Slice key(_start + readInteger<ValueLength>(_start + offset, offsetSize), options);
|
||||
Slice key(_start + readInteger<ValueLength>(_start + offset, offsetSize),
|
||||
options);
|
||||
|
||||
int res;
|
||||
if (key.isString()) {
|
||||
if (key.isString()) {
|
||||
res = key.compareString(attribute);
|
||||
}
|
||||
else if (key.isInteger()) {
|
||||
} else if (key.isInteger()) {
|
||||
// translate key
|
||||
res = key.translate().compareString(attribute);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// invalid key
|
||||
return Slice();
|
||||
}
|
||||
|
@ -585,15 +629,14 @@ Slice Slice::searchObjectKeyBinary (std::string const& attribute,
|
|||
if (res == 0) {
|
||||
// found
|
||||
return Slice(key.start() + key.byteSize(), options);
|
||||
}
|
||||
}
|
||||
|
||||
if (res > 0) {
|
||||
if (index == 0) {
|
||||
return Slice();
|
||||
}
|
||||
r = index - 1;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
l = index + 1;
|
||||
}
|
||||
if (r < l) {
|
||||
|
@ -601,15 +644,17 @@ Slice Slice::searchObjectKeyBinary (std::string const& attribute,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& stream, Slice const* slice) {
|
||||
stream << "[Slice " << valueTypeName(slice->type()) << " (" << slice->hexType() << "), byteSize: " << slice->byteSize() << "]";
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, Slice const* slice) {
|
||||
stream << "[Slice " << valueTypeName(slice->type()) << " ("
|
||||
<< slice->hexType() << "), byteSize: " << slice->byteSize() << "]";
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& stream, Slice const& slice) {
|
||||
std::ostream& operator<<(std::ostream& stream, Slice const& slice) {
|
||||
return operator<<(stream, &slice);
|
||||
}
|
||||
|
||||
static_assert(sizeof(arangodb::velocypack::Slice) == sizeof(void*) + sizeof(void*),
|
||||
static_assert(sizeof(arangodb::velocypack::Slice) ==
|
||||
sizeof(void*) + sizeof(void*),
|
||||
"Slice has an unexpected size");
|
||||
|
|
|
@ -30,31 +30,48 @@
|
|||
|
||||
using namespace arangodb::velocypack;
|
||||
|
||||
char const* arangodb::velocypack::valueTypeName (ValueType type) {
|
||||
char const* arangodb::velocypack::valueTypeName(ValueType type) {
|
||||
switch (type) {
|
||||
case ValueType::None: return "none";
|
||||
case ValueType::Null: return "null";
|
||||
case ValueType::Bool: return "bool";
|
||||
case ValueType::Array: return "array";
|
||||
case ValueType::Object: return "object";
|
||||
case ValueType::Double: return "double";
|
||||
case ValueType::UTCDate: return "utc-date";
|
||||
case ValueType::External: return "external";
|
||||
case ValueType::MinKey: return "min-key";
|
||||
case ValueType::MaxKey: return "max-key";
|
||||
case ValueType::Int: return "int";
|
||||
case ValueType::UInt: return "uint";
|
||||
case ValueType::SmallInt: return "smallint";
|
||||
case ValueType::String: return "string";
|
||||
case ValueType::Binary: return "binary";
|
||||
case ValueType::BCD: return "bcd";
|
||||
case ValueType::Custom: return "custom";
|
||||
case ValueType::None:
|
||||
return "none";
|
||||
case ValueType::Null:
|
||||
return "null";
|
||||
case ValueType::Bool:
|
||||
return "bool";
|
||||
case ValueType::Array:
|
||||
return "array";
|
||||
case ValueType::Object:
|
||||
return "object";
|
||||
case ValueType::Double:
|
||||
return "double";
|
||||
case ValueType::UTCDate:
|
||||
return "utc-date";
|
||||
case ValueType::External:
|
||||
return "external";
|
||||
case ValueType::MinKey:
|
||||
return "min-key";
|
||||
case ValueType::MaxKey:
|
||||
return "max-key";
|
||||
case ValueType::Int:
|
||||
return "int";
|
||||
case ValueType::UInt:
|
||||
return "uint";
|
||||
case ValueType::SmallInt:
|
||||
return "smallint";
|
||||
case ValueType::String:
|
||||
return "string";
|
||||
case ValueType::Binary:
|
||||
return "binary";
|
||||
case ValueType::BCD:
|
||||
return "bcd";
|
||||
case ValueType::Custom:
|
||||
return "custom";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& stream, ValueType type) {
|
||||
std::ostream& operator<<(std::ostream& stream, ValueType type) {
|
||||
stream << valueTypeName(type);
|
||||
return stream;
|
||||
}
|
||||
|
|
|
@ -33,26 +33,25 @@ using namespace arangodb::velocypack;
|
|||
|
||||
Version const Version::BuildVersion(0, 0, 1);
|
||||
|
||||
std::string Version::toString () const {
|
||||
std::string Version::toString() const {
|
||||
std::stringstream version;
|
||||
version << majorValue << "." << minorValue << "." << patchValue;
|
||||
return version.str();
|
||||
}
|
||||
|
||||
int Version::compare (Version const& other) const {
|
||||
int Version::compare(Version const& other) const {
|
||||
if (majorValue != other.majorValue) {
|
||||
return majorValue < other.majorValue ? -1 : 1;
|
||||
}
|
||||
if (minorValue != other.minorValue) {
|
||||
return minorValue < other.minorValue ? -1 : 1;
|
||||
}
|
||||
}
|
||||
if (patchValue != other.patchValue) {
|
||||
return patchValue < other.patchValue ? -1 : 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Version::compare (Version const& lhs, Version const& rhs) {
|
||||
int Version::compare(Version const& lhs, Version const& rhs) {
|
||||
return lhs.compare(rhs);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,43 +30,42 @@
|
|||
#include "velocypack/velocypack-common.h"
|
||||
#include "asm-functions.h"
|
||||
|
||||
size_t JSONStringCopyC (uint8_t* dst, uint8_t const* src, size_t limit) {
|
||||
size_t JSONStringCopyC(uint8_t* dst, uint8_t const* src, size_t limit) {
|
||||
return JSONStringCopyInline(dst, src, limit);
|
||||
}
|
||||
|
||||
size_t JSONStringCopyCheckUtf8C (uint8_t* dst, uint8_t const* src,
|
||||
size_t limit) {
|
||||
size_t JSONStringCopyCheckUtf8C(uint8_t* dst, uint8_t const* src,
|
||||
size_t limit) {
|
||||
return JSONStringCopyCheckUtf8Inline(dst, src, limit);
|
||||
}
|
||||
|
||||
size_t JSONSkipWhiteSpaceC (uint8_t const* ptr, size_t limit) {
|
||||
size_t JSONSkipWhiteSpaceC(uint8_t const* ptr, size_t limit) {
|
||||
return JSONSkipWhiteSpaceInline(ptr, limit);
|
||||
}
|
||||
|
||||
#if defined(__SSE4_2__) && ! defined(NO_SSE42)
|
||||
#if defined(__SSE4_2__) && !defined(NO_SSE42)
|
||||
|
||||
#include <cpuid.h>
|
||||
#include <x86intrin.h>
|
||||
|
||||
static bool HasSSE42 () {
|
||||
static bool HasSSE42() {
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
|
||||
if ((ecx & 0x100000) != 0) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t JSONStringCopySSE42 (uint8_t* dst, uint8_t const* src, size_t limit) {
|
||||
alignas(16) static char const ranges[17]
|
||||
= "\x20\x21\x23\x5b\x5d\xff ";
|
||||
//= "\x01\x1f\"\"\\\\\"\"\"\"\"\"\"\"\"\"";
|
||||
static size_t JSONStringCopySSE42(uint8_t* dst, uint8_t const* src,
|
||||
size_t limit) {
|
||||
alignas(16) static char const ranges[17] =
|
||||
"\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;
|
||||
|
@ -74,8 +73,7 @@ static size_t JSONStringCopySSE42 (uint8_t* dst, uint8_t const* src, size_t limi
|
|||
__m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(src));
|
||||
x = _mm_cmpistri(r, /* 6, */ s, /* 16, */
|
||||
_SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |
|
||||
_SIDD_NEGATIVE_POLARITY |
|
||||
_SIDD_LEAST_SIGNIFICANT);
|
||||
_SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT);
|
||||
if (x < 16) {
|
||||
memcpy(dst, src, x);
|
||||
dst += x;
|
||||
|
@ -95,8 +93,7 @@ static size_t JSONStringCopySSE42 (uint8_t* dst, uint8_t const* src, size_t limi
|
|||
__m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(src));
|
||||
x = _mm_cmpistri(r, /* 6, */ s, /* limit, */
|
||||
_SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |
|
||||
_SIDD_NEGATIVE_POLARITY |
|
||||
_SIDD_LEAST_SIGNIFICANT);
|
||||
_SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT);
|
||||
if (x > static_cast<int>(limit)) {
|
||||
x = static_cast<int>(limit);
|
||||
}
|
||||
|
@ -107,22 +104,20 @@ static size_t JSONStringCopySSE42 (uint8_t* dst, uint8_t const* src, size_t limi
|
|||
return count;
|
||||
}
|
||||
|
||||
static size_t DoInitCopy (uint8_t* dst, uint8_t const* src, size_t limit) {
|
||||
static size_t DoInitCopy(uint8_t* dst, uint8_t const* src, size_t limit) {
|
||||
if (HasSSE42()) {
|
||||
JSONStringCopy = JSONStringCopySSE42;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
JSONStringCopy = JSONStringCopyC;
|
||||
}
|
||||
return (*JSONStringCopy)(dst, src, limit);
|
||||
}
|
||||
|
||||
static size_t JSONStringCopyCheckUtf8SSE42 (uint8_t* dst,
|
||||
uint8_t const* src,
|
||||
size_t limit) {
|
||||
alignas(16) static unsigned char const ranges[17]
|
||||
= "\x20\x21\x23\x5b\x5d\x7f ";
|
||||
//= "\x01\x1f\x80\xff\"\"\\\\\"\"\"\"\"\"\"\"";
|
||||
static size_t JSONStringCopyCheckUtf8SSE42(uint8_t* dst, uint8_t const* src,
|
||||
size_t limit) {
|
||||
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;
|
||||
|
@ -130,8 +125,7 @@ static size_t JSONStringCopyCheckUtf8SSE42 (uint8_t* dst,
|
|||
__m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(src));
|
||||
x = _mm_cmpistri(r, /* 8, */ s, /* 16, */
|
||||
_SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |
|
||||
_SIDD_NEGATIVE_POLARITY |
|
||||
_SIDD_LEAST_SIGNIFICANT);
|
||||
_SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT);
|
||||
if (x < 16) {
|
||||
memcpy(dst, src, x);
|
||||
dst += x;
|
||||
|
@ -151,8 +145,7 @@ static size_t JSONStringCopyCheckUtf8SSE42 (uint8_t* dst,
|
|||
__m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(src));
|
||||
x = _mm_cmpistri(r, /* 8, */ s, /* limit, */
|
||||
_SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |
|
||||
_SIDD_NEGATIVE_POLARITY |
|
||||
_SIDD_LEAST_SIGNIFICANT);
|
||||
_SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT);
|
||||
if (x > static_cast<int>(limit)) {
|
||||
x = static_cast<int>(limit);
|
||||
}
|
||||
|
@ -163,28 +156,26 @@ static size_t JSONStringCopyCheckUtf8SSE42 (uint8_t* dst,
|
|||
return count;
|
||||
}
|
||||
|
||||
static size_t DoInitCopyCheckUtf8 (uint8_t* dst, uint8_t const* src,
|
||||
size_t limit) {
|
||||
static size_t DoInitCopyCheckUtf8(uint8_t* dst, uint8_t const* src,
|
||||
size_t limit) {
|
||||
if (HasSSE42()) {
|
||||
JSONStringCopyCheckUtf8 = JSONStringCopyCheckUtf8SSE42;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
JSONStringCopyCheckUtf8 = JSONStringCopyCheckUtf8C;
|
||||
}
|
||||
return (*JSONStringCopyCheckUtf8)(dst, src, limit);
|
||||
}
|
||||
|
||||
static size_t JSONSkipWhiteSpaceSSE42 (uint8_t const* ptr, size_t limit) {
|
||||
static size_t JSONSkipWhiteSpaceSSE42(uint8_t const* ptr, size_t limit) {
|
||||
alignas(16) static char const white[17] = " \t\n\r ";
|
||||
__m128i const w = _mm_load_si128(reinterpret_cast<__m128i const*>(white));
|
||||
size_t count = 0;
|
||||
int x = 0;
|
||||
while (limit >= 16) {
|
||||
__m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(ptr));
|
||||
x = _mm_cmpistri(w, /* 4, */ s,/* 16, */
|
||||
x = _mm_cmpistri(w, /* 4, */ s, /* 16, */
|
||||
_SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY |
|
||||
_SIDD_NEGATIVE_POLARITY |
|
||||
_SIDD_LEAST_SIGNIFICANT);
|
||||
_SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT);
|
||||
if (x < 16) {
|
||||
ptr += x;
|
||||
count += x;
|
||||
|
@ -198,10 +189,9 @@ static size_t JSONSkipWhiteSpaceSSE42 (uint8_t const* ptr, size_t limit) {
|
|||
return count;
|
||||
}
|
||||
__m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(ptr));
|
||||
x = _mm_cmpistri(w, /* 4, */ s,/* limit, */
|
||||
x = _mm_cmpistri(w, /* 4, */ s, /* limit, */
|
||||
_SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY |
|
||||
_SIDD_NEGATIVE_POLARITY |
|
||||
_SIDD_LEAST_SIGNIFICANT);
|
||||
_SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT);
|
||||
if (static_cast<size_t>(x) > limit) {
|
||||
x = static_cast<int>(limit);
|
||||
}
|
||||
|
@ -210,11 +200,10 @@ static size_t JSONSkipWhiteSpaceSSE42 (uint8_t const* ptr, size_t limit) {
|
|||
return count;
|
||||
}
|
||||
|
||||
static size_t DoInitSkip (uint8_t const* ptr, size_t limit) {
|
||||
static size_t DoInitSkip(uint8_t const* ptr, size_t limit) {
|
||||
if (HasSSE42()) {
|
||||
JSONSkipWhiteSpace = JSONSkipWhiteSpaceSSE42;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
JSONSkipWhiteSpace = JSONSkipWhiteSpaceC;
|
||||
}
|
||||
return (*JSONSkipWhiteSpace)(ptr, limit);
|
||||
|
@ -222,39 +211,38 @@ static size_t DoInitSkip (uint8_t const* ptr, size_t limit) {
|
|||
|
||||
#else
|
||||
|
||||
static size_t DoInitCopy (uint8_t* dst, uint8_t const* src, size_t limit) {
|
||||
static size_t DoInitCopy(uint8_t* dst, uint8_t const* src, size_t limit) {
|
||||
JSONStringCopy = JSONStringCopyC;
|
||||
return JSONStringCopyC(dst, src, limit);
|
||||
}
|
||||
|
||||
static size_t DoInitCopyCheckUtf8 (uint8_t* dst, uint8_t const* src,
|
||||
size_t limit) {
|
||||
static size_t DoInitCopyCheckUtf8(uint8_t* dst, uint8_t const* src,
|
||||
size_t limit) {
|
||||
JSONStringCopyCheckUtf8 = JSONStringCopyCheckUtf8C;
|
||||
return JSONStringCopyCheckUtf8C(dst, src, limit);
|
||||
}
|
||||
|
||||
static size_t DoInitSkip (uint8_t const* ptr, size_t limit) {
|
||||
static size_t DoInitSkip(uint8_t const* ptr, size_t limit) {
|
||||
JSONSkipWhiteSpace = JSONSkipWhiteSpaceC;
|
||||
return JSONSkipWhiteSpace(ptr, limit);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
size_t (*JSONStringCopy)(uint8_t*, uint8_t const*, size_t) = DoInitCopy;
|
||||
size_t (*JSONStringCopyCheckUtf8)(uint8_t*, uint8_t const*, size_t)
|
||||
= DoInitCopyCheckUtf8;
|
||||
size_t (*JSONStringCopyCheckUtf8)(uint8_t*, uint8_t const*,
|
||||
size_t) = DoInitCopyCheckUtf8;
|
||||
size_t (*JSONSkipWhiteSpace)(uint8_t const*, size_t) = DoInitSkip;
|
||||
|
||||
#if defined(COMPILE_VELOCYPACK_ASM_UNITTESTS)
|
||||
|
||||
int testPositions[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 23, 31, 32, 67, 103, 178, 210, 234, 247, 254, 255,
|
||||
-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12,
|
||||
-13, -14, -15, -16, -23, -31, -32, -67, -103, -178,
|
||||
-210, -234, -247, -254, -255 };
|
||||
int testPositions[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||
14, 15, 16, 23, 31, 32, 67, 103, 178, 210, 234, 247, 254, 255,
|
||||
-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14,
|
||||
-15, -16, -23, -31, -32, -67, -103, -178, -210, -234, -247, -254, -255};
|
||||
|
||||
void TestStringCopyCorrectness (uint8_t* src, uint8_t* dst, size_t size) {
|
||||
void TestStringCopyCorrectness(uint8_t* src, uint8_t* dst, size_t size) {
|
||||
size_t copied;
|
||||
|
||||
std::cout << "Performing correctness tests..." << std::endl;
|
||||
|
@ -272,8 +260,7 @@ void TestStringCopyCorrectness (uint8_t* src, uint8_t* dst, size_t size) {
|
|||
size_t pos;
|
||||
if (off >= 0) {
|
||||
pos = off;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pos = size - static_cast<size_t>(-off);
|
||||
}
|
||||
if (pos >= size) {
|
||||
|
@ -281,11 +268,12 @@ void TestStringCopyCorrectness (uint8_t* src, uint8_t* dst, size_t size) {
|
|||
}
|
||||
|
||||
// Test a quote character:
|
||||
merk = src[pos]; src[pos] = '"';
|
||||
merk = src[pos];
|
||||
src[pos] = '"';
|
||||
copied = JSONStringCopy(dst, src, size);
|
||||
if (copied != pos || memcmp(dst, src, copied) != 0) {
|
||||
std::cout << "Error: " << salign << " " << dalign << " "
|
||||
<< i << " " << pos << " " << copied << std::endl;
|
||||
std::cout << "Error: " << salign << " " << dalign << " " << i << " "
|
||||
<< pos << " " << copied << std::endl;
|
||||
}
|
||||
src[pos] = merk;
|
||||
|
||||
|
@ -293,8 +281,8 @@ void TestStringCopyCorrectness (uint8_t* src, uint8_t* dst, size_t size) {
|
|||
src[pos] = '\\';
|
||||
copied = JSONStringCopy(dst, src, size);
|
||||
if (copied != pos || memcmp(dst, src, copied) != 0) {
|
||||
std::cout << "Error: " << salign << " " << dalign << " "
|
||||
<< i << " " << pos << " " << copied << std::endl;
|
||||
std::cout << "Error: " << salign << " " << dalign << " " << i << " "
|
||||
<< pos << " " << copied << std::endl;
|
||||
}
|
||||
src[pos] = merk;
|
||||
|
||||
|
@ -302,8 +290,8 @@ void TestStringCopyCorrectness (uint8_t* src, uint8_t* dst, size_t size) {
|
|||
src[pos] = 1;
|
||||
copied = JSONStringCopy(dst, src, size);
|
||||
if (copied != pos || memcmp(dst, src, copied) != 0) {
|
||||
std::cout << "Error: " << salign << " " << dalign << " "
|
||||
<< i << " " << pos << " " << copied << std::endl;
|
||||
std::cout << "Error: " << salign << " " << dalign << " " << i << " "
|
||||
<< pos << " " << copied << std::endl;
|
||||
}
|
||||
src[pos] = merk;
|
||||
|
||||
|
@ -311,8 +299,8 @@ void TestStringCopyCorrectness (uint8_t* src, uint8_t* dst, size_t size) {
|
|||
src[pos] = 31;
|
||||
copied = JSONStringCopy(dst, src, size);
|
||||
if (copied != pos || memcmp(dst, src, copied) != 0) {
|
||||
std::cout << "Error: " << salign << " " << dalign << " "
|
||||
<< i << " " << pos << " " << copied << std::endl;
|
||||
std::cout << "Error: " << salign << " " << dalign << " " << i << " "
|
||||
<< pos << " " << copied << std::endl;
|
||||
}
|
||||
src[pos] = merk;
|
||||
}
|
||||
|
@ -322,14 +310,14 @@ void TestStringCopyCorrectness (uint8_t* src, uint8_t* dst, size_t size) {
|
|||
}
|
||||
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> totalTime
|
||||
= std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
std::cout << "Tests took altogether " << totalTime.count() << " seconds."
|
||||
std::chrono::duration<double> totalTime =
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
std::cout << "Tests took altogether " << totalTime.count() << " seconds."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
void TestStringCopyCorrectnessCheckUtf8 (uint8_t* src, uint8_t* dst,
|
||||
size_t size) {
|
||||
void TestStringCopyCorrectnessCheckUtf8(uint8_t* src, uint8_t* dst,
|
||||
size_t size) {
|
||||
size_t copied;
|
||||
|
||||
std::cout << "Performing correctness tests (check UTF8)..." << std::endl;
|
||||
|
@ -340,15 +328,14 @@ void TestStringCopyCorrectnessCheckUtf8 (uint8_t* src, uint8_t* dst,
|
|||
src += salign;
|
||||
for (int dalign = 0; dalign < 16; dalign++) {
|
||||
dst += dalign;
|
||||
for (int i = 0;
|
||||
i < static_cast<int>(sizeof(testPositions) / sizeof(int)); i++) {
|
||||
for (int i = 0; i < static_cast<int>(sizeof(testPositions) / sizeof(int));
|
||||
i++) {
|
||||
uint8_t merk;
|
||||
int off = testPositions[i];
|
||||
size_t pos;
|
||||
if (off >= 0) {
|
||||
pos = off;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pos = size - static_cast<size_t>(-off);
|
||||
}
|
||||
if (pos >= size) {
|
||||
|
@ -356,11 +343,12 @@ void TestStringCopyCorrectnessCheckUtf8 (uint8_t* src, uint8_t* dst,
|
|||
}
|
||||
|
||||
// Test a quote character:
|
||||
merk = src[pos]; src[pos] = '"';
|
||||
merk = src[pos];
|
||||
src[pos] = '"';
|
||||
copied = JSONStringCopyCheckUtf8(dst, src, size);
|
||||
if (copied != pos || memcmp(dst, src, copied) != 0) {
|
||||
std::cout << "Error: " << salign << " " << dalign << " "
|
||||
<< i << " " << pos << " " << copied << std::endl;
|
||||
std::cout << "Error: " << salign << " " << dalign << " " << i << " "
|
||||
<< pos << " " << copied << std::endl;
|
||||
}
|
||||
src[pos] = merk;
|
||||
|
||||
|
@ -368,8 +356,8 @@ void TestStringCopyCorrectnessCheckUtf8 (uint8_t* src, uint8_t* dst,
|
|||
src[pos] = '\\';
|
||||
copied = JSONStringCopyCheckUtf8(dst, src, size);
|
||||
if (copied != pos || memcmp(dst, src, copied) != 0) {
|
||||
std::cout << "Error: " << salign << " " << dalign << " "
|
||||
<< i << " " << pos << " " << copied << std::endl;
|
||||
std::cout << "Error: " << salign << " " << dalign << " " << i << " "
|
||||
<< pos << " " << copied << std::endl;
|
||||
}
|
||||
src[pos] = merk;
|
||||
|
||||
|
@ -377,8 +365,8 @@ void TestStringCopyCorrectnessCheckUtf8 (uint8_t* src, uint8_t* dst,
|
|||
src[pos] = 1;
|
||||
copied = JSONStringCopyCheckUtf8(dst, src, size);
|
||||
if (copied != pos || memcmp(dst, src, copied) != 0) {
|
||||
std::cout << "Error: " << salign << " " << dalign << " "
|
||||
<< i << " " << pos << " " << copied << std::endl;
|
||||
std::cout << "Error: " << salign << " " << dalign << " " << i << " "
|
||||
<< pos << " " << copied << std::endl;
|
||||
}
|
||||
src[pos] = merk;
|
||||
|
||||
|
@ -386,8 +374,8 @@ void TestStringCopyCorrectnessCheckUtf8 (uint8_t* src, uint8_t* dst,
|
|||
src[pos] = 31;
|
||||
copied = JSONStringCopyCheckUtf8(dst, src, size);
|
||||
if (copied != pos || memcmp(dst, src, copied) != 0) {
|
||||
std::cout << "Error: " << salign << " " << dalign << " "
|
||||
<< i << " " << pos << " " << copied << std::endl;
|
||||
std::cout << "Error: " << salign << " " << dalign << " " << i << " "
|
||||
<< pos << " " << copied << std::endl;
|
||||
}
|
||||
src[pos] = merk;
|
||||
|
||||
|
@ -395,8 +383,8 @@ void TestStringCopyCorrectnessCheckUtf8 (uint8_t* src, uint8_t* dst,
|
|||
src[pos] = 0x80;
|
||||
copied = JSONStringCopyCheckUtf8(dst, src, size);
|
||||
if (copied != pos || memcmp(dst, src, copied) != 0) {
|
||||
std::cout << "Error: " << salign << " " << dalign << " "
|
||||
<< i << " " << pos << " " << copied << std::endl;
|
||||
std::cout << "Error: " << salign << " " << dalign << " " << i << " "
|
||||
<< pos << " " << copied << std::endl;
|
||||
}
|
||||
src[pos] = merk;
|
||||
}
|
||||
|
@ -406,31 +394,30 @@ void TestStringCopyCorrectnessCheckUtf8 (uint8_t* src, uint8_t* dst,
|
|||
}
|
||||
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> totalTime
|
||||
= std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
std::cout << "Tests took altogether " << totalTime.count() << " seconds."
|
||||
std::chrono::duration<double> totalTime =
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
std::cout << "Tests took altogether " << totalTime.count() << " seconds."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
void TestSkipWhiteSpaceCorrectness (uint8_t* src, size_t size) {
|
||||
void TestSkipWhiteSpaceCorrectness(uint8_t* src, size_t size) {
|
||||
size_t copied;
|
||||
|
||||
std::cout << "Performing correctness tests for whitespace skipping..."
|
||||
std::cout << "Performing correctness tests for whitespace skipping..."
|
||||
<< std::endl;
|
||||
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
for (int salign = 0; salign < 16; salign++) {
|
||||
src += salign;
|
||||
for (int i = 0;
|
||||
i < static_cast<int>(sizeof(testPositions) / sizeof(int)); i++) {
|
||||
for (int i = 0; i < static_cast<int>(sizeof(testPositions) / sizeof(int));
|
||||
i++) {
|
||||
uint8_t merk;
|
||||
int off = testPositions[i];
|
||||
size_t pos;
|
||||
if (off >= 0) {
|
||||
pos = off;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pos = size - static_cast<size_t>(-off);
|
||||
}
|
||||
if (pos >= size) {
|
||||
|
@ -438,11 +425,12 @@ void TestSkipWhiteSpaceCorrectness (uint8_t* src, size_t size) {
|
|||
}
|
||||
|
||||
// Test a non-whitespace character:
|
||||
merk = src[pos]; src[pos] = 'x';
|
||||
merk = src[pos];
|
||||
src[pos] = 'x';
|
||||
copied = JSONSkipWhiteSpace(src, size);
|
||||
if (copied != pos) {
|
||||
std::cout << "Error: " << salign << " "
|
||||
<< i << " " << pos << " " << copied << std::endl;
|
||||
std::cout << "Error: " << salign << " " << i << " " << pos << " "
|
||||
<< copied << std::endl;
|
||||
}
|
||||
src[pos] = merk;
|
||||
}
|
||||
|
@ -450,13 +438,14 @@ void TestSkipWhiteSpaceCorrectness (uint8_t* src, size_t size) {
|
|||
}
|
||||
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> totalTime
|
||||
= std::chrono::duration_cast<std::chrono::duration<double>>(now-start);
|
||||
std::cout << "Whitespace tests took altogether " << totalTime.count()
|
||||
std::chrono::duration<double> totalTime =
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
std::cout << "Whitespace tests took altogether " << totalTime.count()
|
||||
<< " seconds." << std::endl;
|
||||
}
|
||||
|
||||
void RaceStringCopy (uint8_t* dst, uint8_t* src, size_t size, int repeat, int&akku) {
|
||||
void RaceStringCopy(uint8_t* dst, uint8_t* src, size_t size, int repeat,
|
||||
int& akku) {
|
||||
size_t copied;
|
||||
|
||||
std::cout << "\nNow racing for the repeated full string, "
|
||||
|
@ -471,17 +460,16 @@ void RaceStringCopy (uint8_t* dst, uint8_t* src, size_t size, int repeat, int&ak
|
|||
auto now = std::chrono::high_resolution_clock::now();
|
||||
src[size] = 'a' + (size % 26);
|
||||
|
||||
auto totalTime
|
||||
= std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
auto totalTime =
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
<< std::endl;
|
||||
std::cout << "Time to copy string of length " << size
|
||||
<< " on average is: " << totalTime.count() / repeat << "."
|
||||
<< std::endl;
|
||||
std::cout << "Bytes copied per second: "
|
||||
<< (double) size * (double) repeat / totalTime.count()
|
||||
<< std::endl;
|
||||
<< (double)size * (double)repeat / totalTime.count() << std::endl;
|
||||
|
||||
std::cout << "\nNow racing for the repeated full string, "
|
||||
<< "now unaligned target...\n" << std::endl;
|
||||
|
@ -495,21 +483,20 @@ void RaceStringCopy (uint8_t* dst, uint8_t* src, size_t size, int repeat, int&ak
|
|||
now = std::chrono::high_resolution_clock::now();
|
||||
dst--;
|
||||
|
||||
totalTime
|
||||
= std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
totalTime =
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
<< std::endl;
|
||||
std::cout << "Time to copy string of length " << size
|
||||
<< " on average is: " << totalTime.count() / repeat << "."
|
||||
<< std::endl;
|
||||
std::cout << "Bytes copied per second: "
|
||||
<< (double) size * (double) repeat / totalTime.count()
|
||||
<< std::endl;
|
||||
<< (double)size * (double)repeat / totalTime.count() << std::endl;
|
||||
}
|
||||
|
||||
void RaceStringCopyCheckUtf8 (uint8_t* dst, uint8_t* src,
|
||||
size_t size, int repeat, int& akku) {
|
||||
void RaceStringCopyCheckUtf8(uint8_t* dst, uint8_t* src, size_t size,
|
||||
int repeat, int& akku) {
|
||||
size_t copied;
|
||||
|
||||
std::cout << "\nNow racing for the repeated (check UTF8) full string, "
|
||||
|
@ -524,19 +511,20 @@ void RaceStringCopyCheckUtf8 (uint8_t* dst, uint8_t* src,
|
|||
auto now = std::chrono::high_resolution_clock::now();
|
||||
src[size] = 'a' + (size % 26);
|
||||
|
||||
auto totalTime
|
||||
= std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
auto totalTime =
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
<< std::endl;
|
||||
std::cout << "Time to copy string of length " << size
|
||||
<< " on average is: " << totalTime.count() / repeat << "."
|
||||
<< std::endl;
|
||||
std::cout << "Bytes copied per second: "
|
||||
<< (double) size * (double) repeat / totalTime.count()
|
||||
<< std::endl;
|
||||
<< (double)size * (double)repeat / totalTime.count() << std::endl;
|
||||
|
||||
std::cout << "\nNow racing for the repeated full string, now unaligned target...\n" << std::endl;
|
||||
std::cout
|
||||
<< "\nNow racing for the repeated full string, now unaligned target...\n"
|
||||
<< std::endl;
|
||||
|
||||
dst++;
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
|
@ -547,42 +535,39 @@ void RaceStringCopyCheckUtf8 (uint8_t* dst, uint8_t* src,
|
|||
now = std::chrono::high_resolution_clock::now();
|
||||
dst--;
|
||||
|
||||
totalTime
|
||||
= std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
totalTime =
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
<< std::endl;
|
||||
std::cout << "Time to copy string of length " << size
|
||||
<< " on average is: " << totalTime.count() / repeat << "."
|
||||
<< std::endl;
|
||||
std::cout << "Bytes copied per second: "
|
||||
<< (double) size * (double) repeat / totalTime.count()
|
||||
<< std::endl;
|
||||
<< (double)size * (double)repeat / totalTime.count() << std::endl;
|
||||
|
||||
std::cout << "\nNow comparing with strcpy...\n" << std::endl;
|
||||
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
for (int j = 0; j < repeat; j++) {
|
||||
//strcpy((char*) dst, (char*) src);
|
||||
memcpy((char*) dst, (char*) src, size);
|
||||
|
||||
// strcpy((char*) dst, (char*) src);
|
||||
memcpy((char*)dst, (char*)src, size);
|
||||
}
|
||||
now = std::chrono::high_resolution_clock::now();
|
||||
|
||||
totalTime
|
||||
= std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
totalTime =
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
<< std::endl;
|
||||
std::cout << "Time to copy string of length " << size
|
||||
<< " on average is: " << totalTime.count() / repeat << "."
|
||||
<< std::endl;
|
||||
std::cout << "Bytes copied per second: "
|
||||
<< (double) size * (double) repeat / totalTime.count()
|
||||
<< std::endl;
|
||||
<< (double)size * (double)repeat / totalTime.count() << std::endl;
|
||||
}
|
||||
|
||||
void RaceSkipWhiteSpace (uint8_t* src, size_t size, int repeat, int& akku) {
|
||||
void RaceSkipWhiteSpace(uint8_t* src, size_t size, int repeat, int& akku) {
|
||||
size_t copied;
|
||||
|
||||
std::cout << "\nNow racing for the repeated full string...\n" << std::endl;
|
||||
|
@ -596,45 +581,44 @@ void RaceSkipWhiteSpace (uint8_t* src, size_t size, int repeat, int& akku) {
|
|||
}
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
|
||||
auto totalTime
|
||||
= std::chrono::duration_cast<std::chrono::duration<double>>(now-start);
|
||||
auto totalTime =
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
<< std::endl;
|
||||
std::cout << "Time to skip white string of length " << size
|
||||
<< " on average is: " << totalTime.count() / repeat << "."
|
||||
<< std::endl;
|
||||
std::cout << "Bytes skipped per second: "
|
||||
<< (double) size * (double) repeat / totalTime.count()
|
||||
<< std::endl;
|
||||
<< (double)size * (double)repeat / totalTime.count() << std::endl;
|
||||
|
||||
std::cout << "\nNow comparing with strlen...\n" << std::endl;
|
||||
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
for (int j = 0; j < repeat; j++) {
|
||||
copied = strlen((char*) src);
|
||||
copied = strlen((char*)src);
|
||||
// Fake activity for the compiler:
|
||||
src[0] = (j & 0xf) + 1;
|
||||
akku = akku * 13 + copied;
|
||||
}
|
||||
now = std::chrono::high_resolution_clock::now();
|
||||
|
||||
totalTime
|
||||
= std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
totalTime =
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
|
||||
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
std::cout << "Race took altogether " << totalTime.count() << " seconds."
|
||||
<< std::endl;
|
||||
std::cout << "Time to strlen string of length " << size
|
||||
<< " on average is: " << totalTime.count() / repeat << "."
|
||||
<< std::endl;
|
||||
std::cout << "Bytes scanned per second: "
|
||||
<< (double) size * (double) repeat / totalTime.count()
|
||||
<< std::endl;
|
||||
<< (double)size * (double)repeat / totalTime.count() << std::endl;
|
||||
}
|
||||
|
||||
int main (int argc, char* argv[]) {
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 4) {
|
||||
std::cout << "Usage: " << argv[0] << " SIZE REPEAT CORRECTNESS" << std::endl;
|
||||
std::cout << "Usage: " << argv[0] << " SIZE REPEAT CORRECTNESS"
|
||||
<< std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -645,23 +629,23 @@ int main (int argc, char* argv[]) {
|
|||
std::cout << "Size: " << size << std::endl;
|
||||
std::cout << "Repeat:" << repeat << std::endl;
|
||||
|
||||
uint8_t* src = new uint8_t[size+17];
|
||||
uint8_t* dst = new uint8_t[size+17];
|
||||
std::cout << "Src pointer: " << (void*) src << std::endl;
|
||||
std::cout << "Dst pointer: " << (void*) dst << std::endl;
|
||||
for (size_t i = 0; i < size+16; i++) {
|
||||
uint8_t* src = new uint8_t[size + 17];
|
||||
uint8_t* dst = new uint8_t[size + 17];
|
||||
std::cout << "Src pointer: " << (void*)src << std::endl;
|
||||
std::cout << "Dst pointer: " << (void*)dst << std::endl;
|
||||
for (size_t i = 0; i < size + 16; i++) {
|
||||
src[i] = 'a' + (i % 26);
|
||||
}
|
||||
src[size+16] = 0;
|
||||
src[size + 16] = 0;
|
||||
|
||||
if (docorrectness > 0) {
|
||||
TestStringCopyCorrectness(src, dst, size);
|
||||
TestStringCopyCorrectness(src, dst, size);
|
||||
}
|
||||
|
||||
RaceStringCopy(dst, src, size, repeat, akku);
|
||||
|
||||
|
||||
if (docorrectness > 0) {
|
||||
TestStringCopyCorrectnessCheckUtf8(src, dst, size);
|
||||
TestStringCopyCorrectnessCheckUtf8(src, dst, size);
|
||||
}
|
||||
|
||||
RaceStringCopyCheckUtf8(dst, src, size, repeat, akku);
|
||||
|
@ -670,10 +654,10 @@ int main (int argc, char* argv[]) {
|
|||
|
||||
// Now do the whitespace skipping tests/measurements:
|
||||
static char const whitetab[17] = " \t \n \r";
|
||||
for (size_t i = 0; i < size+16; i++) {
|
||||
for (size_t i = 0; i < size + 16; i++) {
|
||||
src[i] = whitetab[i % 16];
|
||||
}
|
||||
src[size+16] = 0;
|
||||
src[size + 16] = 0;
|
||||
|
||||
if (docorrectness > 0) {
|
||||
TestSkipWhiteSpaceCorrectness(src, size);
|
||||
|
|
|
@ -30,41 +30,35 @@
|
|||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
static inline size_t JSONStringCopyInline (uint8_t* dst, uint8_t const* src,
|
||||
size_t limit) {
|
||||
static inline size_t JSONStringCopyInline(uint8_t* dst, uint8_t const* src,
|
||||
size_t limit) {
|
||||
// Copy up to limit uint8_t from src to dst.
|
||||
// Stop at the first control character or backslash or double quote.
|
||||
// Report the number of bytes copied. May copy less bytes, for example
|
||||
// for alignment reasons.
|
||||
size_t count = limit;
|
||||
while (count > 0 &&
|
||||
*src >= 32 &&
|
||||
*src != '\\' &&
|
||||
*src != '"') {
|
||||
while (count > 0 && *src >= 32 && *src != '\\' && *src != '"') {
|
||||
*dst++ = *src++;
|
||||
count--;
|
||||
}
|
||||
return limit - count;
|
||||
}
|
||||
|
||||
size_t JSONStringCopyC (uint8_t* dst, uint8_t const* src, size_t limit);
|
||||
size_t JSONStringCopyC(uint8_t* dst, uint8_t const* src, size_t limit);
|
||||
extern size_t (*JSONStringCopy)(uint8_t*, uint8_t const*, size_t);
|
||||
|
||||
// Now a version which also stops at high bit set bytes:
|
||||
|
||||
static inline size_t JSONStringCopyCheckUtf8Inline (uint8_t* dst,
|
||||
uint8_t const* src,
|
||||
size_t limit) {
|
||||
static inline size_t JSONStringCopyCheckUtf8Inline(uint8_t* dst,
|
||||
uint8_t const* src,
|
||||
size_t limit) {
|
||||
// Copy up to limit uint8_t from src to dst.
|
||||
// Stop at the first control character or backslash or double quote.
|
||||
// Also stop at byte with high bit set.
|
||||
// Report the number of bytes copied. May copy less bytes, for example
|
||||
// for alignment reasons.
|
||||
size_t count = limit;
|
||||
while (count > 0 &&
|
||||
*src >= 32 &&
|
||||
*src != '\\' &&
|
||||
*src != '"' &&
|
||||
while (count > 0 && *src >= 32 && *src != '\\' && *src != '"' &&
|
||||
*src < 0x80) {
|
||||
*dst++ = *src++;
|
||||
count--;
|
||||
|
@ -72,29 +66,25 @@ static inline size_t JSONStringCopyCheckUtf8Inline (uint8_t* dst,
|
|||
return limit - count;
|
||||
}
|
||||
|
||||
size_t JSONStringCopyCheckUtf8C (uint8_t* dst, uint8_t const* src,
|
||||
size_t limit);
|
||||
size_t JSONStringCopyCheckUtf8C(uint8_t* dst, uint8_t const* src, size_t limit);
|
||||
extern size_t (*JSONStringCopyCheckUtf8)(uint8_t*, uint8_t const*, size_t);
|
||||
|
||||
// White space skipping:
|
||||
|
||||
static inline size_t JSONSkipWhiteSpaceInline (uint8_t const* ptr,
|
||||
size_t limit) {
|
||||
static inline size_t JSONSkipWhiteSpaceInline(uint8_t const* ptr,
|
||||
size_t limit) {
|
||||
// Skip up to limit uint8_t from ptr as long as they are whitespace.
|
||||
// Advance ptr and return the number of skipped bytes.
|
||||
size_t count = limit;
|
||||
while (count > 0 &&
|
||||
(*ptr == ' ' ||
|
||||
*ptr == '\t' ||
|
||||
*ptr == '\n' ||
|
||||
*ptr == '\r')) {
|
||||
(*ptr == ' ' || *ptr == '\t' || *ptr == '\n' || *ptr == '\r')) {
|
||||
ptr++;
|
||||
count--;
|
||||
}
|
||||
return limit - count;
|
||||
}
|
||||
|
||||
size_t JSONSkipWhiteSpaceC (uint8_t const* ptr, size_t limit);
|
||||
size_t JSONSkipWhiteSpaceC(uint8_t const* ptr, size_t limit);
|
||||
extern size_t (*JSONSkipWhiteSpace)(uint8_t const*, size_t);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,51 +27,56 @@
|
|||
#include <cstdlib>
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
namespace velocypack {
|
||||
|
||||
// Compression function for Merkle-Damgard construction.
|
||||
// This function is generated using the framework provided.
|
||||
static inline uint64_t mix(uint64_t h) {
|
||||
h ^= h >> 23;
|
||||
h *= 0x2127599bf4325c37ULL;
|
||||
h ^= h >> 47;
|
||||
// Compression function for Merkle-Damgard construction.
|
||||
// This function is generated using the framework provided.
|
||||
static inline uint64_t mix(uint64_t h) {
|
||||
h ^= h >> 23;
|
||||
h *= 0x2127599bf4325c37ULL;
|
||||
h ^= h >> 47;
|
||||
|
||||
return h;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
uint64_t fasthash64(const void *buf, size_t len, uint64_t seed)
|
||||
{
|
||||
const uint64_t m = 0x880355f21e6d1965ULL;
|
||||
const uint64_t *pos = (const uint64_t *)buf;
|
||||
const uint64_t *end = pos + (len / 8);
|
||||
const unsigned char *pos2;
|
||||
uint64_t h = seed ^ (len * m);
|
||||
uint64_t v;
|
||||
uint64_t fasthash64(const void *buf, size_t len, uint64_t seed) {
|
||||
const uint64_t m = 0x880355f21e6d1965ULL;
|
||||
const uint64_t *pos = (const uint64_t *)buf;
|
||||
const uint64_t *end = pos + (len / 8);
|
||||
const unsigned char *pos2;
|
||||
uint64_t h = seed ^ (len * m);
|
||||
uint64_t v;
|
||||
|
||||
while (pos != end) {
|
||||
v = *pos++;
|
||||
h ^= mix(v);
|
||||
h *= m;
|
||||
}
|
||||
while (pos != end) {
|
||||
v = *pos++;
|
||||
h ^= mix(v);
|
||||
h *= m;
|
||||
}
|
||||
|
||||
pos2 = (const unsigned char*)pos;
|
||||
v = 0;
|
||||
pos2 = (const unsigned char *)pos;
|
||||
v = 0;
|
||||
|
||||
switch (len & 7) {
|
||||
case 7: v ^= (uint64_t)pos2[6] << 48;
|
||||
case 6: v ^= (uint64_t)pos2[5] << 40;
|
||||
case 5: v ^= (uint64_t)pos2[4] << 32;
|
||||
case 4: v ^= (uint64_t)pos2[3] << 24;
|
||||
case 3: v ^= (uint64_t)pos2[2] << 16;
|
||||
case 2: v ^= (uint64_t)pos2[1] << 8;
|
||||
case 1: v ^= (uint64_t)pos2[0];
|
||||
h ^= mix(v);
|
||||
h *= m;
|
||||
}
|
||||
switch (len & 7) {
|
||||
case 7:
|
||||
v ^= (uint64_t)pos2[6] << 48;
|
||||
case 6:
|
||||
v ^= (uint64_t)pos2[5] << 40;
|
||||
case 5:
|
||||
v ^= (uint64_t)pos2[4] << 32;
|
||||
case 4:
|
||||
v ^= (uint64_t)pos2[3] << 24;
|
||||
case 3:
|
||||
v ^= (uint64_t)pos2[2] << 16;
|
||||
case 2:
|
||||
v ^= (uint64_t)pos2[1] << 8;
|
||||
case 1:
|
||||
v ^= (uint64_t)pos2[0];
|
||||
h ^= mix(v);
|
||||
h *= m;
|
||||
}
|
||||
|
||||
return mix(h);
|
||||
}
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
return mix(h);
|
||||
}
|
||||
|
||||
} // namespace arangodb::velocypack
|
||||
} // namespace arangodb
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
* printf("%s", buf);
|
||||
* }
|
||||
*
|
||||
* [1] http://florian.loitsch.com/publications/dtoa-pldi2010.pdf
|
||||
* [1] http://florian.loitsch.com/publications/dtoa-pldi2010.pdf
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
|
@ -29,339 +29,326 @@
|
|||
#include "velocypack/velocypack-common.h"
|
||||
#include "powers.h"
|
||||
|
||||
#define fracmask 0x000FFFFFFFFFFFFFU
|
||||
#define expmask 0x7FF0000000000000U
|
||||
#define fracmask 0x000FFFFFFFFFFFFFU
|
||||
#define expmask 0x7FF0000000000000U
|
||||
#define hiddenbit 0x0010000000000000U
|
||||
#define signmask 0x8000000000000000U
|
||||
#define expbias (1023 + 52)
|
||||
#define signmask 0x8000000000000000U
|
||||
#define expbias (1023 + 52)
|
||||
|
||||
#define absv(n) ((n) < 0 ? -(n) : (n))
|
||||
#define minv(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
// forward for fpconv function
|
||||
int fpconv_dtoa (double fp, char dest[24]);
|
||||
}
|
||||
namespace velocypack {
|
||||
// forward for fpconv function
|
||||
int fpconv_dtoa(double fp, char dest[24]);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t tens[] = {
|
||||
10000000000000000000U, 1000000000000000000U, 100000000000000000U,
|
||||
10000000000000000U, 1000000000000000U, 100000000000000U,
|
||||
10000000000000U, 1000000000000U, 100000000000U,
|
||||
10000000000U, 1000000000U, 100000000U,
|
||||
10000000U, 1000000U, 100000U,
|
||||
10000U, 1000U, 100U,
|
||||
10U, 1U
|
||||
};
|
||||
10000000000000000U, 1000000000000000U, 100000000000000U,
|
||||
10000000000000U, 1000000000000U, 100000000000U,
|
||||
10000000000U, 1000000000U, 100000000U,
|
||||
10000000U, 1000000U, 100000U,
|
||||
10000U, 1000U, 100U,
|
||||
10U, 1U};
|
||||
|
||||
static inline uint64_t get_dbits(double d)
|
||||
{
|
||||
union {
|
||||
double dbl;
|
||||
uint64_t i;
|
||||
} dbl_bits = { d };
|
||||
static inline uint64_t get_dbits(double d) {
|
||||
union {
|
||||
double dbl;
|
||||
uint64_t i;
|
||||
} dbl_bits = {d};
|
||||
|
||||
return dbl_bits.i;
|
||||
return dbl_bits.i;
|
||||
}
|
||||
|
||||
static Fp build_fp(double d)
|
||||
{
|
||||
uint64_t bits = get_dbits(d);
|
||||
static Fp build_fp(double d) {
|
||||
uint64_t bits = get_dbits(d);
|
||||
|
||||
Fp fp;
|
||||
fp.frac = bits & fracmask;
|
||||
fp.exp = (bits & expmask) >> 52;
|
||||
Fp fp;
|
||||
fp.frac = bits & fracmask;
|
||||
fp.exp = (bits & expmask) >> 52;
|
||||
|
||||
if(fp.exp) {
|
||||
fp.frac += hiddenbit;
|
||||
fp.exp -= expbias;
|
||||
if (fp.exp) {
|
||||
fp.frac += hiddenbit;
|
||||
fp.exp -= expbias;
|
||||
|
||||
} else {
|
||||
fp.exp = -expbias + 1;
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
static void normalize(Fp* fp) {
|
||||
while ((fp->frac & hiddenbit) == 0) {
|
||||
fp->frac <<= 1;
|
||||
fp->exp--;
|
||||
}
|
||||
|
||||
int shift = 64 - 52 - 1;
|
||||
fp->frac <<= shift;
|
||||
fp->exp -= shift;
|
||||
}
|
||||
|
||||
static void get_normalized_boundaries(Fp* fp, Fp* lower, Fp* upper) {
|
||||
upper->frac = (fp->frac << 1) + 1;
|
||||
upper->exp = fp->exp - 1;
|
||||
|
||||
while ((upper->frac & (hiddenbit << 1)) == 0) {
|
||||
upper->frac <<= 1;
|
||||
upper->exp--;
|
||||
}
|
||||
|
||||
int u_shift = 64 - 52 - 2;
|
||||
|
||||
upper->frac <<= u_shift;
|
||||
upper->exp = upper->exp - u_shift;
|
||||
|
||||
int l_shift = fp->frac == hiddenbit ? 2 : 1;
|
||||
|
||||
lower->frac = (fp->frac << l_shift) - 1;
|
||||
lower->exp = fp->exp - l_shift;
|
||||
|
||||
lower->frac <<= lower->exp - upper->exp;
|
||||
lower->exp = upper->exp;
|
||||
}
|
||||
|
||||
static Fp multiply(Fp* a, Fp* b) {
|
||||
const uint64_t lomask = 0x00000000FFFFFFFF;
|
||||
|
||||
uint64_t ah_bl = (a->frac >> 32) * (b->frac & lomask);
|
||||
uint64_t al_bh = (a->frac & lomask) * (b->frac >> 32);
|
||||
uint64_t al_bl = (a->frac & lomask) * (b->frac & lomask);
|
||||
uint64_t ah_bh = (a->frac >> 32) * (b->frac >> 32);
|
||||
|
||||
uint64_t tmp = (ah_bl & lomask) + (al_bh & lomask) + (al_bl >> 32);
|
||||
/* round up */
|
||||
tmp += 1U << 31;
|
||||
|
||||
Fp fp = {ah_bh + (ah_bl >> 32) + (al_bh >> 32) + (tmp >> 32),
|
||||
a->exp + b->exp + 64};
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
static void round_digit(char* digits, int ndigits, uint64_t delta, uint64_t rem,
|
||||
uint64_t kappa, uint64_t frac) {
|
||||
while (rem < frac && delta - rem >= kappa &&
|
||||
(rem + kappa < frac || frac - rem > rem + kappa - frac)) {
|
||||
digits[ndigits - 1]--;
|
||||
rem += kappa;
|
||||
}
|
||||
}
|
||||
|
||||
static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K) {
|
||||
uint64_t wfrac = upper->frac - fp->frac;
|
||||
uint64_t delta = upper->frac - lower->frac;
|
||||
|
||||
Fp one;
|
||||
one.frac = 1ULL << -upper->exp;
|
||||
one.exp = upper->exp;
|
||||
|
||||
uint64_t part1 = upper->frac >> -one.exp;
|
||||
uint64_t part2 = upper->frac & (one.frac - 1);
|
||||
|
||||
int idx = 0, kappa = 10;
|
||||
uint64_t* divp;
|
||||
/* 1000000000 */
|
||||
for (divp = tens + 10; kappa > 0; divp++) {
|
||||
uint64_t div = *divp;
|
||||
unsigned digit = static_cast<unsigned>(part1 / div);
|
||||
|
||||
if (digit || idx) {
|
||||
digits[idx++] = digit + '0';
|
||||
}
|
||||
|
||||
part1 -= digit * div;
|
||||
kappa--;
|
||||
|
||||
uint64_t tmp = (part1 << -one.exp) + part2;
|
||||
if (tmp <= delta) {
|
||||
*K += kappa;
|
||||
round_digit(digits, idx, delta, tmp, div << -one.exp, wfrac);
|
||||
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
/* 10 */
|
||||
uint64_t* unit = tens + 18;
|
||||
|
||||
while (true) {
|
||||
part2 *= 10;
|
||||
delta *= 10;
|
||||
kappa--;
|
||||
|
||||
unsigned digit = static_cast<unsigned>(part2 >> -one.exp);
|
||||
if (digit || idx) {
|
||||
digits[idx++] = digit + '0';
|
||||
}
|
||||
|
||||
part2 &= one.frac - 1;
|
||||
if (part2 < delta) {
|
||||
*K += kappa;
|
||||
round_digit(digits, idx, delta, part2, one.frac, wfrac * *unit);
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
unit--;
|
||||
}
|
||||
}
|
||||
|
||||
static int grisu2(double d, char* digits, int* K) {
|
||||
Fp w = build_fp(d);
|
||||
|
||||
Fp lower, upper;
|
||||
get_normalized_boundaries(&w, &lower, &upper);
|
||||
|
||||
normalize(&w);
|
||||
|
||||
int k;
|
||||
Fp cp = find_cachedpow10(upper.exp, &k);
|
||||
|
||||
w = multiply(&w, &cp);
|
||||
upper = multiply(&upper, &cp);
|
||||
lower = multiply(&lower, &cp);
|
||||
|
||||
lower.frac++;
|
||||
upper.frac--;
|
||||
|
||||
*K = -k;
|
||||
|
||||
return generate_digits(&w, &upper, &lower, digits, K);
|
||||
}
|
||||
|
||||
static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg) {
|
||||
int exp = absv(K + ndigits - 1);
|
||||
|
||||
/* write plain integer */
|
||||
if (K >= 0 && (exp < (ndigits + 7))) {
|
||||
memcpy(dest, digits, ndigits);
|
||||
memset(dest + ndigits, '0', K);
|
||||
|
||||
return ndigits + K;
|
||||
}
|
||||
|
||||
/* write decimal w/o scientific notation */
|
||||
if (K < 0 && (K > -7 || exp < 4)) {
|
||||
int offset = ndigits - absv(K);
|
||||
/* fp < 1.0 -> write leading zero */
|
||||
if (offset <= 0) {
|
||||
offset = -offset;
|
||||
dest[0] = '0';
|
||||
dest[1] = '.';
|
||||
memset(dest + 2, '0', offset);
|
||||
memcpy(dest + offset + 2, digits, ndigits);
|
||||
|
||||
return ndigits + 2 + offset;
|
||||
|
||||
/* fp > 1.0 */
|
||||
} else {
|
||||
fp.exp = -expbias + 1;
|
||||
}
|
||||
memcpy(dest, digits, offset);
|
||||
dest[offset] = '.';
|
||||
memcpy(dest + offset + 1, digits + offset, ndigits - offset);
|
||||
|
||||
return fp;
|
||||
return ndigits + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* write decimal w/ scientific notation */
|
||||
ndigits = minv(ndigits, 18 - neg);
|
||||
|
||||
int idx = 0;
|
||||
dest[idx++] = digits[0];
|
||||
|
||||
if (ndigits > 1) {
|
||||
dest[idx++] = '.';
|
||||
memcpy(dest + idx, digits + 1, ndigits - 1);
|
||||
idx += ndigits - 1;
|
||||
}
|
||||
|
||||
dest[idx++] = 'e';
|
||||
|
||||
char sign = K + ndigits - 1 < 0 ? '-' : '+';
|
||||
dest[idx++] = sign;
|
||||
|
||||
int cent = 0;
|
||||
|
||||
if (exp > 99) {
|
||||
cent = exp / 100;
|
||||
dest[idx++] = cent + '0';
|
||||
exp -= cent * 100;
|
||||
}
|
||||
if (exp > 9) {
|
||||
int dec = exp / 10;
|
||||
dest[idx++] = dec + '0';
|
||||
exp -= dec * 10;
|
||||
|
||||
} else if (cent) {
|
||||
dest[idx++] = '0';
|
||||
}
|
||||
|
||||
dest[idx++] = exp % 10 + '0';
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static void normalize(Fp* fp)
|
||||
{
|
||||
while ((fp->frac & hiddenbit) == 0) {
|
||||
fp->frac <<= 1;
|
||||
fp->exp--;
|
||||
}
|
||||
static int filter_special(double fp, char* dest) {
|
||||
if (fp == 0.0) {
|
||||
dest[0] = '0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
int shift = 64 - 52 - 1;
|
||||
fp->frac <<= shift;
|
||||
fp->exp -= shift;
|
||||
uint64_t bits = get_dbits(fp);
|
||||
|
||||
bool nan = (bits & expmask) == expmask;
|
||||
|
||||
if (!nan) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bits & fracmask) {
|
||||
dest[0] = 'N';
|
||||
dest[1] = 'a';
|
||||
dest[2] = 'N';
|
||||
|
||||
} else {
|
||||
dest[0] = 'i';
|
||||
dest[1] = 'n';
|
||||
dest[2] = 'f';
|
||||
}
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
static void get_normalized_boundaries(Fp* fp, Fp* lower, Fp* upper)
|
||||
{
|
||||
upper->frac = (fp->frac << 1) + 1;
|
||||
upper->exp = fp->exp - 1;
|
||||
int arangodb::velocypack::fpconv_dtoa(double d, char dest[24]) {
|
||||
char digits[18];
|
||||
|
||||
while ((upper->frac & (hiddenbit << 1)) == 0) {
|
||||
upper->frac <<= 1;
|
||||
upper->exp--;
|
||||
}
|
||||
int str_len = 0;
|
||||
bool neg = false;
|
||||
|
||||
int u_shift = 64 - 52 - 2;
|
||||
if (get_dbits(d) & signmask) {
|
||||
dest[0] = '-';
|
||||
str_len++;
|
||||
neg = true;
|
||||
}
|
||||
|
||||
upper->frac <<= u_shift;
|
||||
upper->exp = upper->exp - u_shift;
|
||||
int spec = filter_special(d, dest + str_len);
|
||||
|
||||
if (spec) {
|
||||
return str_len + spec;
|
||||
}
|
||||
|
||||
int l_shift = fp->frac == hiddenbit ? 2 : 1;
|
||||
// initialize digits[0] to satisfy scan_build
|
||||
digits[0] = '\0';
|
||||
|
||||
lower->frac = (fp->frac << l_shift) - 1;
|
||||
lower->exp = fp->exp - l_shift;
|
||||
int K = 0;
|
||||
int ndigits = grisu2(d, digits, &K);
|
||||
|
||||
str_len += emit_digits(digits, ndigits, dest + str_len, K, neg);
|
||||
|
||||
lower->frac <<= lower->exp - upper->exp;
|
||||
lower->exp = upper->exp;
|
||||
}
|
||||
|
||||
static Fp multiply(Fp* a, Fp* b)
|
||||
{
|
||||
const uint64_t lomask = 0x00000000FFFFFFFF;
|
||||
|
||||
uint64_t ah_bl = (a->frac >> 32) * (b->frac & lomask);
|
||||
uint64_t al_bh = (a->frac & lomask) * (b->frac >> 32);
|
||||
uint64_t al_bl = (a->frac & lomask) * (b->frac & lomask);
|
||||
uint64_t ah_bh = (a->frac >> 32) * (b->frac >> 32);
|
||||
|
||||
uint64_t tmp = (ah_bl & lomask) + (al_bh & lomask) + (al_bl >> 32);
|
||||
/* round up */
|
||||
tmp += 1U << 31;
|
||||
|
||||
Fp fp = {
|
||||
ah_bh + (ah_bl >> 32) + (al_bh >> 32) + (tmp >> 32),
|
||||
a->exp + b->exp + 64
|
||||
};
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
static void round_digit(char* digits, int ndigits, uint64_t delta, uint64_t rem, uint64_t kappa, uint64_t frac)
|
||||
{
|
||||
while (rem < frac && delta - rem >= kappa &&
|
||||
(rem + kappa < frac || frac - rem > rem + kappa - frac)) {
|
||||
|
||||
digits[ndigits - 1]--;
|
||||
rem += kappa;
|
||||
}
|
||||
}
|
||||
|
||||
static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K)
|
||||
{
|
||||
uint64_t wfrac = upper->frac - fp->frac;
|
||||
uint64_t delta = upper->frac - lower->frac;
|
||||
|
||||
Fp one;
|
||||
one.frac = 1ULL << -upper->exp;
|
||||
one.exp = upper->exp;
|
||||
|
||||
uint64_t part1 = upper->frac >> -one.exp;
|
||||
uint64_t part2 = upper->frac & (one.frac - 1);
|
||||
|
||||
int idx = 0, kappa = 10;
|
||||
uint64_t* divp;
|
||||
/* 1000000000 */
|
||||
for(divp = tens + 10; kappa > 0; divp++) {
|
||||
|
||||
uint64_t div = *divp;
|
||||
unsigned digit = static_cast<unsigned>(part1 / div);
|
||||
|
||||
if (digit || idx) {
|
||||
digits[idx++] = digit + '0';
|
||||
}
|
||||
|
||||
part1 -= digit * div;
|
||||
kappa--;
|
||||
|
||||
uint64_t tmp = (part1 <<-one.exp) + part2;
|
||||
if (tmp <= delta) {
|
||||
*K += kappa;
|
||||
round_digit(digits, idx, delta, tmp, div << -one.exp, wfrac);
|
||||
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
/* 10 */
|
||||
uint64_t* unit = tens + 18;
|
||||
|
||||
while(true) {
|
||||
part2 *= 10;
|
||||
delta *= 10;
|
||||
kappa--;
|
||||
|
||||
unsigned digit = static_cast<unsigned>(part2 >> -one.exp);
|
||||
if (digit || idx) {
|
||||
digits[idx++] = digit + '0';
|
||||
}
|
||||
|
||||
part2 &= one.frac - 1;
|
||||
if (part2 < delta) {
|
||||
*K += kappa;
|
||||
round_digit(digits, idx, delta, part2, one.frac, wfrac * *unit);
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
unit--;
|
||||
}
|
||||
}
|
||||
|
||||
static int grisu2(double d, char* digits, int* K)
|
||||
{
|
||||
Fp w = build_fp(d);
|
||||
|
||||
Fp lower, upper;
|
||||
get_normalized_boundaries(&w, &lower, &upper);
|
||||
|
||||
normalize(&w);
|
||||
|
||||
int k;
|
||||
Fp cp = find_cachedpow10(upper.exp, &k);
|
||||
|
||||
w = multiply(&w, &cp);
|
||||
upper = multiply(&upper, &cp);
|
||||
lower = multiply(&lower, &cp);
|
||||
|
||||
lower.frac++;
|
||||
upper.frac--;
|
||||
|
||||
*K = -k;
|
||||
|
||||
return generate_digits(&w, &upper, &lower, digits, K);
|
||||
}
|
||||
|
||||
static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
|
||||
{
|
||||
int exp = absv(K + ndigits - 1);
|
||||
|
||||
/* write plain integer */
|
||||
if(K >= 0 && (exp < (ndigits + 7))) {
|
||||
memcpy(dest, digits, ndigits);
|
||||
memset(dest + ndigits, '0', K);
|
||||
|
||||
return ndigits + K;
|
||||
}
|
||||
|
||||
/* write decimal w/o scientific notation */
|
||||
if(K < 0 && (K > -7 || exp < 4)) {
|
||||
int offset = ndigits - absv(K);
|
||||
/* fp < 1.0 -> write leading zero */
|
||||
if(offset <= 0) {
|
||||
offset = -offset;
|
||||
dest[0] = '0';
|
||||
dest[1] = '.';
|
||||
memset(dest + 2, '0', offset);
|
||||
memcpy(dest + offset + 2, digits, ndigits);
|
||||
|
||||
return ndigits + 2 + offset;
|
||||
|
||||
/* fp > 1.0 */
|
||||
} else {
|
||||
memcpy(dest, digits, offset);
|
||||
dest[offset] = '.';
|
||||
memcpy(dest + offset + 1, digits + offset, ndigits - offset);
|
||||
|
||||
return ndigits + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* write decimal w/ scientific notation */
|
||||
ndigits = minv(ndigits, 18 - neg);
|
||||
|
||||
int idx = 0;
|
||||
dest[idx++] = digits[0];
|
||||
|
||||
if(ndigits > 1) {
|
||||
dest[idx++] = '.';
|
||||
memcpy(dest + idx, digits + 1, ndigits - 1);
|
||||
idx += ndigits - 1;
|
||||
}
|
||||
|
||||
dest[idx++] = 'e';
|
||||
|
||||
char sign = K + ndigits - 1 < 0 ? '-' : '+';
|
||||
dest[idx++] = sign;
|
||||
|
||||
int cent = 0;
|
||||
|
||||
if(exp > 99) {
|
||||
cent = exp / 100;
|
||||
dest[idx++] = cent + '0';
|
||||
exp -= cent * 100;
|
||||
}
|
||||
if(exp > 9) {
|
||||
int dec = exp / 10;
|
||||
dest[idx++] = dec + '0';
|
||||
exp -= dec * 10;
|
||||
|
||||
} else if(cent) {
|
||||
dest[idx++] = '0';
|
||||
}
|
||||
|
||||
dest[idx++] = exp % 10 + '0';
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static int filter_special(double fp, char* dest)
|
||||
{
|
||||
if(fp == 0.0) {
|
||||
dest[0] = '0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64_t bits = get_dbits(fp);
|
||||
|
||||
bool nan = (bits & expmask) == expmask;
|
||||
|
||||
if(!nan) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(bits & fracmask) {
|
||||
dest[0] = 'N'; dest[1] = 'a'; dest[2] = 'N';
|
||||
|
||||
} else {
|
||||
dest[0] = 'i'; dest[1] = 'n'; dest[2] = 'f';
|
||||
}
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
int arangodb::velocypack::fpconv_dtoa (double d, char dest[24])
|
||||
{
|
||||
char digits[18];
|
||||
|
||||
int str_len = 0;
|
||||
bool neg = false;
|
||||
|
||||
if(get_dbits(d) & signmask) {
|
||||
dest[0] = '-';
|
||||
str_len++;
|
||||
neg = true;
|
||||
}
|
||||
|
||||
int spec = filter_special(d, dest + str_len);
|
||||
|
||||
if(spec) {
|
||||
return str_len + spec;
|
||||
}
|
||||
|
||||
// initialize digits[0] to satisfy scan_build
|
||||
digits[0] = '\0';
|
||||
|
||||
int K = 0;
|
||||
int ndigits = grisu2(d, digits, &K);
|
||||
|
||||
str_len += emit_digits(digits, ndigits, dest + str_len, K, neg);
|
||||
|
||||
return str_len;
|
||||
return str_len;
|
||||
}
|
||||
|
|
|
@ -5,90 +5,129 @@
|
|||
|
||||
#include "velocypack/velocypack-common.h"
|
||||
|
||||
#define npowers 87
|
||||
#define steppowers 8
|
||||
#define npowers 87
|
||||
#define steppowers 8
|
||||
#define firstpower -348 /* 10 ^ -348 */
|
||||
|
||||
#define expmax -32
|
||||
#define expmin -60
|
||||
|
||||
#define expmax -32
|
||||
#define expmin -60
|
||||
|
||||
typedef struct Fp {
|
||||
uint64_t frac;
|
||||
int exp;
|
||||
uint64_t frac;
|
||||
int exp;
|
||||
} Fp;
|
||||
|
||||
static Fp powers_ten[] = {
|
||||
{ 18054884314459144840U, -1220 }, { 13451937075301367670U, -1193 },
|
||||
{ 10022474136428063862U, -1166 }, { 14934650266808366570U, -1140 },
|
||||
{ 11127181549972568877U, -1113 }, { 16580792590934885855U, -1087 },
|
||||
{ 12353653155963782858U, -1060 }, { 18408377700990114895U, -1034 },
|
||||
{ 13715310171984221708U, -1007 }, { 10218702384817765436U, -980 },
|
||||
{ 15227053142812498563U, -954 }, { 11345038669416679861U, -927 },
|
||||
{ 16905424996341287883U, -901 }, { 12595523146049147757U, -874 },
|
||||
{ 9384396036005875287U, -847 }, { 13983839803942852151U, -821 },
|
||||
{ 10418772551374772303U, -794 }, { 15525180923007089351U, -768 },
|
||||
{ 11567161174868858868U, -741 }, { 17236413322193710309U, -715 },
|
||||
{ 12842128665889583758U, -688 }, { 9568131466127621947U, -661 },
|
||||
{ 14257626930069360058U, -635 }, { 10622759856335341974U, -608 },
|
||||
{ 15829145694278690180U, -582 }, { 11793632577567316726U, -555 },
|
||||
{ 17573882009934360870U, -529 }, { 13093562431584567480U, -502 },
|
||||
{ 9755464219737475723U, -475 }, { 14536774485912137811U, -449 },
|
||||
{ 10830740992659433045U, -422 }, { 16139061738043178685U, -396 },
|
||||
{ 12024538023802026127U, -369 }, { 17917957937422433684U, -343 },
|
||||
{ 13349918974505688015U, -316 }, { 9946464728195732843U, -289 },
|
||||
{ 14821387422376473014U, -263 }, { 11042794154864902060U, -236 },
|
||||
{ 16455045573212060422U, -210 }, { 12259964326927110867U, -183 },
|
||||
{ 18268770466636286478U, -157 }, { 13611294676837538539U, -130 },
|
||||
{ 10141204801825835212U, -103 }, { 15111572745182864684U, -77 },
|
||||
{ 11258999068426240000U, -50 }, { 16777216000000000000U, -24 },
|
||||
{ 12500000000000000000U, 3 }, { 9313225746154785156U, 30 },
|
||||
{ 13877787807814456755U, 56 }, { 10339757656912845936U, 83 },
|
||||
{ 15407439555097886824U, 109 }, { 11479437019748901445U, 136 },
|
||||
{ 17105694144590052135U, 162 }, { 12744735289059618216U, 189 },
|
||||
{ 9495567745759798747U, 216 }, { 14149498560666738074U, 242 },
|
||||
{ 10542197943230523224U, 269 }, { 15709099088952724970U, 295 },
|
||||
{ 11704190886730495818U, 322 }, { 17440603504673385349U, 348 },
|
||||
{ 12994262207056124023U, 375 }, { 9681479787123295682U, 402 },
|
||||
{ 14426529090290212157U, 428 }, { 10748601772107342003U, 455 },
|
||||
{ 16016664761464807395U, 481 }, { 11933345169920330789U, 508 },
|
||||
{ 17782069995880619868U, 534 }, { 13248674568444952270U, 561 },
|
||||
{ 9871031767461413346U, 588 }, { 14708983551653345445U, 614 },
|
||||
{ 10959046745042015199U, 641 }, { 16330252207878254650U, 667 },
|
||||
{ 12166986024289022870U, 694 }, { 18130221999122236476U, 720 },
|
||||
{ 13508068024458167312U, 747 }, { 10064294952495520794U, 774 },
|
||||
{ 14996968138956309548U, 800 }, { 11173611982879273257U, 827 },
|
||||
{ 16649979327439178909U, 853 }, { 12405201291620119593U, 880 },
|
||||
{ 9242595204427927429U, 907 }, { 13772540099066387757U, 933 },
|
||||
{ 10261342003245940623U, 960 }, { 15290591125556738113U, 986 },
|
||||
{ 11392378155556871081U, 1013 }, { 16975966327722178521U, 1039 },
|
||||
{ 12648080533535911531U, 1066 }
|
||||
};
|
||||
static Fp powers_ten[] = {{18054884314459144840U, -1220},
|
||||
{13451937075301367670U, -1193},
|
||||
{10022474136428063862U, -1166},
|
||||
{14934650266808366570U, -1140},
|
||||
{11127181549972568877U, -1113},
|
||||
{16580792590934885855U, -1087},
|
||||
{12353653155963782858U, -1060},
|
||||
{18408377700990114895U, -1034},
|
||||
{13715310171984221708U, -1007},
|
||||
{10218702384817765436U, -980},
|
||||
{15227053142812498563U, -954},
|
||||
{11345038669416679861U, -927},
|
||||
{16905424996341287883U, -901},
|
||||
{12595523146049147757U, -874},
|
||||
{9384396036005875287U, -847},
|
||||
{13983839803942852151U, -821},
|
||||
{10418772551374772303U, -794},
|
||||
{15525180923007089351U, -768},
|
||||
{11567161174868858868U, -741},
|
||||
{17236413322193710309U, -715},
|
||||
{12842128665889583758U, -688},
|
||||
{9568131466127621947U, -661},
|
||||
{14257626930069360058U, -635},
|
||||
{10622759856335341974U, -608},
|
||||
{15829145694278690180U, -582},
|
||||
{11793632577567316726U, -555},
|
||||
{17573882009934360870U, -529},
|
||||
{13093562431584567480U, -502},
|
||||
{9755464219737475723U, -475},
|
||||
{14536774485912137811U, -449},
|
||||
{10830740992659433045U, -422},
|
||||
{16139061738043178685U, -396},
|
||||
{12024538023802026127U, -369},
|
||||
{17917957937422433684U, -343},
|
||||
{13349918974505688015U, -316},
|
||||
{9946464728195732843U, -289},
|
||||
{14821387422376473014U, -263},
|
||||
{11042794154864902060U, -236},
|
||||
{16455045573212060422U, -210},
|
||||
{12259964326927110867U, -183},
|
||||
{18268770466636286478U, -157},
|
||||
{13611294676837538539U, -130},
|
||||
{10141204801825835212U, -103},
|
||||
{15111572745182864684U, -77},
|
||||
{11258999068426240000U, -50},
|
||||
{16777216000000000000U, -24},
|
||||
{12500000000000000000U, 3},
|
||||
{9313225746154785156U, 30},
|
||||
{13877787807814456755U, 56},
|
||||
{10339757656912845936U, 83},
|
||||
{15407439555097886824U, 109},
|
||||
{11479437019748901445U, 136},
|
||||
{17105694144590052135U, 162},
|
||||
{12744735289059618216U, 189},
|
||||
{9495567745759798747U, 216},
|
||||
{14149498560666738074U, 242},
|
||||
{10542197943230523224U, 269},
|
||||
{15709099088952724970U, 295},
|
||||
{11704190886730495818U, 322},
|
||||
{17440603504673385349U, 348},
|
||||
{12994262207056124023U, 375},
|
||||
{9681479787123295682U, 402},
|
||||
{14426529090290212157U, 428},
|
||||
{10748601772107342003U, 455},
|
||||
{16016664761464807395U, 481},
|
||||
{11933345169920330789U, 508},
|
||||
{17782069995880619868U, 534},
|
||||
{13248674568444952270U, 561},
|
||||
{9871031767461413346U, 588},
|
||||
{14708983551653345445U, 614},
|
||||
{10959046745042015199U, 641},
|
||||
{16330252207878254650U, 667},
|
||||
{12166986024289022870U, 694},
|
||||
{18130221999122236476U, 720},
|
||||
{13508068024458167312U, 747},
|
||||
{10064294952495520794U, 774},
|
||||
{14996968138956309548U, 800},
|
||||
{11173611982879273257U, 827},
|
||||
{16649979327439178909U, 853},
|
||||
{12405201291620119593U, 880},
|
||||
{9242595204427927429U, 907},
|
||||
{13772540099066387757U, 933},
|
||||
{10261342003245940623U, 960},
|
||||
{15290591125556738113U, 986},
|
||||
{11392378155556871081U, 1013},
|
||||
{16975966327722178521U, 1039},
|
||||
{12648080533535911531U, 1066}};
|
||||
|
||||
static Fp find_cachedpow10(int exp, int* k)
|
||||
{
|
||||
const double one_log_ten = 0.30102999566398114;
|
||||
static Fp find_cachedpow10(int exp, int* k) {
|
||||
const double one_log_ten = 0.30102999566398114;
|
||||
|
||||
int approx = static_cast<int>(-(exp + npowers) * one_log_ten);
|
||||
int idx = (approx - firstpower) / steppowers;
|
||||
int approx = static_cast<int>(-(exp + npowers) * one_log_ten);
|
||||
int idx = (approx - firstpower) / steppowers;
|
||||
|
||||
while(1) {
|
||||
int current = exp + powers_ten[idx].exp + 64;
|
||||
while (1) {
|
||||
int current = exp + powers_ten[idx].exp + 64;
|
||||
|
||||
if(current < expmin) {
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(current > expmax) {
|
||||
idx--;
|
||||
continue;
|
||||
}
|
||||
|
||||
*k = (firstpower + idx * steppowers);
|
||||
|
||||
return powers_ten[idx];
|
||||
if (current < expmin) {
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current > expmax) {
|
||||
idx--;
|
||||
continue;
|
||||
}
|
||||
|
||||
*k = (firstpower + idx * steppowers);
|
||||
|
||||
return powers_ten[idx];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,17 +33,18 @@ 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 () {
|
||||
return static_cast<int64_t>(std::chrono::system_clock::now().time_since_epoch().count() / std::chrono::milliseconds(1).count());
|
||||
int64_t arangodb::velocypack::currentUTCDateValue() {
|
||||
return static_cast<int64_t>(
|
||||
std::chrono::system_clock::now().time_since_epoch().count() /
|
||||
std::chrono::milliseconds(1).count());
|
||||
}
|
||||
|
||||
static_assert(sizeof(arangodb::velocypack::ValueLength) >= sizeof(SIZE_MAX),
|
||||
"invalid value for SIZE_MAX");
|
||||
|
||||
|
|
Loading…
Reference in New Issue