summaryrefslogtreecommitdiff
path: root/ext/librethinkdbxx/src/datum.h
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@zerotier.com>2018-04-25 06:39:02 -0700
committerGitHub <noreply@github.com>2018-04-25 06:39:02 -0700
commit42ec780a6f6eedef4d8b1d8218bd72fc6ed75cc0 (patch)
tree7bf86c4d92d6a0f77eced79bfc33313c62c7b6dd /ext/librethinkdbxx/src/datum.h
parent18c9dc8a0649c866eff9f299f20fa5b19c502e52 (diff)
parent4608880fb06700822d01e9e5d6729fcdeb82b64b (diff)
downloadinfinitytier-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.h287
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;
+};
+
+}