1
0
Fork 0

updated vpack library

This commit is contained in:
Jan Steemann 2015-11-24 10:32:58 +01:00
parent e4a3c462c7
commit d24b46bb71
35 changed files with 3807 additions and 3820 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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;
}

View File

@ -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");

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -29,6 +29,5 @@
using namespace arangodb::velocypack;
// default options instance
// default options instance
Options Options::Defaults;

View File

@ -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 () {
}
}
}

View File

@ -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");

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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");