diff options
author | Adam Ierymenko <adam.ierymenko@zerotier.com> | 2018-04-25 06:39:02 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-25 06:39:02 -0700 |
commit | 42ec780a6f6eedef4d8b1d8218bd72fc6ed75cc0 (patch) | |
tree | 7bf86c4d92d6a0f77eced79bfc33313c62c7b6dd /ext/librethinkdbxx/src/datum.h | |
parent | 18c9dc8a0649c866eff9f299f20fa5b19c502e52 (diff) | |
parent | 4608880fb06700822d01e9e5d6729fcdeb82b64b (diff) | |
download | infinitytier-42ec780a6f6eedef4d8b1d8218bd72fc6ed75cc0.tar.gz infinitytier-42ec780a6f6eedef4d8b1d8218bd72fc6ed75cc0.zip |
Merge branch 'dev' into netbsd-support
Diffstat (limited to 'ext/librethinkdbxx/src/datum.h')
-rw-r--r-- | ext/librethinkdbxx/src/datum.h | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/ext/librethinkdbxx/src/datum.h b/ext/librethinkdbxx/src/datum.h new file mode 100644 index 00000000..051e2ca2 --- /dev/null +++ b/ext/librethinkdbxx/src/datum.h @@ -0,0 +1,287 @@ +#pragma once + +#include <string> +#include <vector> +#include <map> +#include <functional> + +#include "protocol_defs.h" +#include "error.h" +#include "types.h" + +namespace RethinkDB { + +class Cursor; + +// The type of data stored in a RethinkDB database. +// The following JSON types are represented in a Datum as +// * null -> Nil +// * boolean -> bool +// * number -> double +// * unicode strings -> std::string +// * array -> Array (aka std::vector<Datum> +// * object -> Object (aka std::map<std::string, Datum>> +// Datums can also contain one of the following extra types +// * binary strings -> Binary +// * timestamps -> Time +// * points. lines and polygons -> not implemented +class Datum { +public: + Datum() : type(Type::INVALID), value() {} + Datum(Nil) : type(Type::NIL), value() { } + Datum(bool boolean_) : type(Type::BOOLEAN), value(boolean_) { } + Datum(double number_) : type(Type::NUMBER), value(number_) { } + Datum(const std::string& string_) : type(Type::STRING), value(string_) { } + Datum(std::string&& string_) : type(Type::STRING), value(std::move(string_)) { } + Datum(const Array& array_) : type(Type::ARRAY), value(array_) { } + Datum(Array&& array_) : type(Type::ARRAY), value(std::move(array_)) { } + Datum(const Binary& binary) : type(Type::BINARY), value(binary) { } + Datum(Binary&& binary) : type(Type::BINARY), value(std::move(binary)) { } + Datum(const Time time) : type(Type::TIME), value(time) { } + Datum(const Object& object_) : type(Type::OBJECT), value(object_) { } + Datum(Object&& object_) : type(Type::OBJECT), value(std::move(object_)) { } + Datum(const Datum& other) : type(other.type), value(other.type, other.value) { } + Datum(Datum&& other) : type(other.type), value(other.type, std::move(other.value)) { } + + Datum& operator=(const Datum& other) { + value.destroy(type); + type = other.type; + value.set(type, other.value); + return *this; + } + + Datum& operator=(Datum&& other) { + value.destroy(type); + type = other.type; + value.set(type, std::move(other.value)); + return *this; + } + + Datum(unsigned short number_) : Datum(static_cast<double>(number_)) { } + Datum(signed short number_) : Datum(static_cast<double>(number_)) { } + Datum(unsigned int number_) : Datum(static_cast<double>(number_)) { } + Datum(signed int number_) : Datum(static_cast<double>(number_)) { } + Datum(unsigned long number_) : Datum(static_cast<double>(number_)) { } + Datum(signed long number_) : Datum(static_cast<double>(number_)) { } + Datum(unsigned long long number_) : Datum(static_cast<double>(number_)) { } + Datum(signed long long number_) : Datum(static_cast<double>(number_)) { } + + Datum(Protocol::Term::TermType type) : Datum(static_cast<double>(type)) { } + Datum(const char* string) : Datum(static_cast<std::string>(string)) { } + + // Cursors are implicitly converted into datums + Datum(Cursor&&); + Datum(const Cursor&); + + template <class T> + Datum(const std::map<std::string, T>& map) : type(Type::OBJECT), value(Object()) { + for (const auto& it : map) { + value.object.emplace(it.left, Datum(it.right)); + } + } + + template <class T> + Datum(std::map<std::string, T>&& map) : type(Type::OBJECT), value(Object()) { + for (auto& it : map) { + value.object.emplace(it.first, Datum(std::move(it.second))); + } + } + + template <class T> + Datum(const std::vector<T>& vec) : type(Type::ARRAY), value(Array()) { + for (const auto& it : vec) { + value.array.emplace_back(it); + } + } + + template <class T> + Datum(std::vector<T>&& vec) : type(Type::ARRAY), value(Array()) { + for (auto& it : vec) { + value.array.emplace_back(std::move(it)); + } + } + + ~Datum() { + value.destroy(type); + } + + // Apply a visitor + template <class R, class F, class ...A> + R apply(F f, A&& ...args) const & { + switch (type) { + case Type::NIL: return f(Nil(), std::forward<A>(args)...); break; + case Type::BOOLEAN: return f(value.boolean, std::forward<A>(args)...); break; + case Type::NUMBER: return f(value.number, std::forward<A>(args)...); break; + case Type::STRING: return f(value.string, std::forward<A>(args)...); break; + case Type::OBJECT: return f(value.object, std::forward<A>(args)...); break; + case Type::ARRAY: return f(value.array, std::forward<A>(args)...); break; + case Type::BINARY: return f(value.binary, std::forward<A>(args)...); break; + case Type::TIME: return f(value.time, std::forward<A>(args)...); break; + default: + throw Error("internal error: no such datum type %d", static_cast<int>(type)); + } + } + + template <class R, class F, class ...A> + R apply(F f, A&& ...args) && { + switch (type) { + case Type::NIL: return f(Nil(), std::forward<A>(args)...); break; + case Type::BOOLEAN: return f(std::move(value.boolean), std::forward<A>(args)...); break; + case Type::NUMBER: return f(std::move(value.number), std::forward<A>(args)...); break; + case Type::STRING: return f(std::move(value.string), std::forward<A>(args)...); break; + case Type::OBJECT: return f(std::move(value.object), std::forward<A>(args)...); break; + case Type::ARRAY: return f(std::move(value.array), std::forward<A>(args)...); break; + case Type::BINARY: return f(std::move(value.binary), std::forward<A>(args)...); break; + case Type::TIME: return f(std::move(value.time), std::forward<A>(args)...); break; + default: + throw Error("internal error: no such datum type %d", static_cast<int>(type)); + } + } + + bool is_nil() const; + bool is_boolean() const; + bool is_number() const; + bool is_string() const; + bool is_object() const; + bool is_array() const; + bool is_binary() const; + bool is_time() const; + + // get_* returns nullptr if the datum has a different type + + bool* get_boolean(); + const bool* get_boolean() const; + double* get_number(); + const double* get_number() const; + std::string* get_string(); + const std::string* get_string() const; + Object* get_object(); + const Object* get_object() const; + Datum* get_field(std::string); + const Datum* get_field(std::string) const; + Array* get_array(); + const Array* get_array() const; + Datum* get_nth(size_t); + const Datum* get_nth(size_t) const; + Binary* get_binary(); + const Binary* get_binary() const; + Time* get_time(); + const Time* get_time() const; + + // extract_* throws an exception if the types don't match + + bool& extract_boolean(); + double& extract_number(); + std::string& extract_string(); + Object& extract_object(); + Datum& extract_field(std::string); + Array& extract_array(); + Datum& extract_nth(size_t); + Binary& extract_binary(); + Time& extract_time(); + + // negative, zero or positive if this datum is smaller, identical or larger than the other one, respectively + // This is meant to match the results of RethinkDB's comparison operators + int compare(const Datum&) const; + + // Deep equality + bool operator== (const Datum&) const; + + // Recusively replace non-JSON types into objects that represent them + Datum to_raw() const; + + // Recursively replace objects with a $reql_type$ field into the datum they represent + Datum from_raw() const; + + template <class json_writer_t> void write_json(json_writer_t *writer) const; + + std::string as_json() const; + static Datum from_json(const std::string&); + + bool is_valid() const { return type != Type::INVALID; } + +private: + enum class Type { + INVALID, // default constructed + ARRAY, BOOLEAN, NIL, NUMBER, OBJECT, BINARY, STRING, TIME + // POINT, LINE, POLYGON + }; + Type type; + + union datum_value { + bool boolean; + double number; + std::string string; + Object object; + Array array; + Binary binary; + Time time; + + datum_value() { } + datum_value(bool boolean_) : boolean(boolean_) { } + datum_value(double number_) : number(number_) { } + datum_value(const std::string& string_) : string(string_) { } + datum_value(std::string&& string_) : string(std::move(string_)) { } + datum_value(const Object& object_) : object(object_) { } + datum_value(Object&& object_) : object(std::move(object_)) { } + datum_value(const Array& array_) : array(array_) { } + datum_value(Array&& array_) : array(std::move(array_)) { } + datum_value(const Binary& binary_) : binary(binary_) { } + datum_value(Binary&& binary_) : binary(std::move(binary_)) { } + datum_value(Time time) : time(std::move(time)) { } + + datum_value(Type type, const datum_value& other){ + set(type, other); + } + + datum_value(Type type, datum_value&& other){ + set(type, std::move(other)); + } + + void set(Type type, datum_value&& other) { + switch(type){ + case Type::NIL: case Type::INVALID: break; + case Type::BOOLEAN: new (this) bool(other.boolean); break; + case Type::NUMBER: new (this) double(other.number); break; + case Type::STRING: new (this) std::string(std::move(other.string)); break; + case Type::OBJECT: new (this) Object(std::move(other.object)); break; + case Type::ARRAY: new (this) Array(std::move(other.array)); break; + case Type::BINARY: new (this) Binary(std::move(other.binary)); break; + case Type::TIME: new (this) Time(std::move(other.time)); break; + } + } + + void set(Type type, const datum_value& other) { + switch(type){ + case Type::NIL: case Type::INVALID: break; + case Type::BOOLEAN: new (this) bool(other.boolean); break; + case Type::NUMBER: new (this) double(other.number); break; + case Type::STRING: new (this) std::string(other.string); break; + case Type::OBJECT: new (this) Object(other.object); break; + case Type::ARRAY: new (this) Array(other.array); break; + case Type::BINARY: new (this) Binary(other.binary); break; + case Type::TIME: new (this) Time(other.time); break; + } + } + + void destroy(Type type) { + switch(type){ + case Type::INVALID: break; + case Type::NIL: break; + case Type::BOOLEAN: break; + case Type::NUMBER: break; + case Type::STRING: { typedef std::string str; string.~str(); } break; + case Type::OBJECT: object.~Object(); break; + case Type::ARRAY: array.~Array(); break; + case Type::BINARY: binary.~Binary(); break; + case Type::TIME: time.~Time(); break; + } + } + + ~datum_value() { } + }; + + datum_value value; +}; + +} |