TypedValue getters return references

Reviewers: buda

Reviewed By: buda

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D113
This commit is contained in:
Mislav Bradac 2017-03-13 15:55:48 +01:00
parent 3e0b12f646
commit a5a15673de
2 changed files with 346 additions and 284 deletions

View File

@ -1,58 +1,58 @@
#include "query/backend/cpp/typed_value.hpp" #include "query/backend/cpp/typed_value.hpp"
#include <fmt/format.h>
#include <cmath> #include <cmath>
#include <fmt/format.h>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include "utils/assert.hpp" #include "utils/assert.hpp"
TypedValue::TypedValue(const PropertyValue& value) { TypedValue::TypedValue(const PropertyValue &value) {
switch (value.type()) { switch (value.type()) {
case PropertyValue::Type::Null: case PropertyValue::Type::Null:
type_ = Type::Null; type_ = Type::Null;
return; return;
case PropertyValue::Type::Bool: case PropertyValue::Type::Bool:
type_ = Type::Bool; type_ = Type::Bool;
bool_v = value.Value<bool>(); bool_v = value.Value<bool>();
return; return;
case PropertyValue::Type::Int: case PropertyValue::Type::Int:
type_ = Type::Int; type_ = Type::Int;
int_v = value.Value<int64_t>(); int_v = value.Value<int64_t>();
return; return;
case PropertyValue::Type::Double: case PropertyValue::Type::Double:
type_ = Type::Double; type_ = Type::Double;
double_v = value.Value<double>(); double_v = value.Value<double>();
case PropertyValue::Type::String: case PropertyValue::Type::String:
type_ = Type::String; type_ = Type::String;
new (&string_v) std::string(value.Value<std::string>()); new (&string_v) std::string(value.Value<std::string>());
case PropertyValue::Type::List: case PropertyValue::Type::List:
type_ = Type::List; type_ = Type::List;
auto vec = value.Value<std::vector<PropertyValue>>(); auto vec = value.Value<std::vector<PropertyValue>>();
new (&list_v) std::vector<TypedValue>(vec.begin(), vec.end()); new (&list_v) std::vector<TypedValue>(vec.begin(), vec.end());
return; return;
} }
permanent_fail("Unsupported type"); permanent_fail("Unsupported type");
} }
TypedValue::operator PropertyValue() const { TypedValue::operator PropertyValue() const {
switch (type_) { switch (type_) {
case TypedValue::Type::Null: case TypedValue::Type::Null:
return PropertyValue::Null; return PropertyValue::Null;
case TypedValue::Type::Bool: case TypedValue::Type::Bool:
return PropertyValue(bool_v); return PropertyValue(bool_v);
case TypedValue::Type::Int: case TypedValue::Type::Int:
return PropertyValue(int_v); return PropertyValue(int_v);
case TypedValue::Type::Double: case TypedValue::Type::Double:
return PropertyValue(double_v); return PropertyValue(double_v);
case TypedValue::Type::String: case TypedValue::Type::String:
return PropertyValue(string_v); return PropertyValue(string_v);
case TypedValue::Type::List: case TypedValue::Type::List:
return PropertyValue( return PropertyValue(
std::vector<PropertyValue>(list_v.begin(), list_v.end())); std::vector<PropertyValue>(list_v.begin(), list_v.end()));
default: default:
throw TypedValueException( throw TypedValueException(
"Unsupported conversion from TypedValue to PropertyValue"); "Unsupported conversion from TypedValue to PropertyValue");
} }
} }
@ -61,32 +61,28 @@ TypedValue::operator PropertyValue() const {
// Other solution would be to add additional overloads for references, for // Other solution would be to add additional overloads for references, for
// example Value<string&>. // example Value<string&>.
// Value extraction template instantiations // Value extraction template instantiations
template <> template <> const bool &TypedValue::Value<bool>() const {
bool TypedValue::Value<bool>() const {
if (type_ != TypedValue::Type::Bool) { if (type_ != TypedValue::Type::Bool) {
throw TypedValueException("Incompatible template param and type"); throw TypedValueException("Incompatible template param and type");
} }
return bool_v; return bool_v;
} }
template <> template <> const int64_t &TypedValue::Value<int64_t>() const {
int64_t TypedValue::Value<int64_t>() const {
if (type_ != TypedValue::Type::Int) { if (type_ != TypedValue::Type::Int) {
throw TypedValueException("Incompatible template param and type"); throw TypedValueException("Incompatible template param and type");
} }
return int_v; return int_v;
} }
template <> template <> const double &TypedValue::Value<double>() const {
double TypedValue::Value<double>() const {
if (type_ != TypedValue::Type::Double) { if (type_ != TypedValue::Type::Double) {
throw TypedValueException("Incompatible template param and type"); throw TypedValueException("Incompatible template param and type");
} }
return double_v; return double_v;
} }
template <> template <> const std::string &TypedValue::Value<std::string>() const {
std::string TypedValue::Value<std::string>() const {
if (type_ != TypedValue::Type::String) { if (type_ != TypedValue::Type::String) {
throw TypedValueException("Incompatible template param and type"); throw TypedValueException("Incompatible template param and type");
} }
@ -94,7 +90,8 @@ std::string TypedValue::Value<std::string>() const {
} }
template <> template <>
std::vector<TypedValue> TypedValue::Value<std::vector<TypedValue>>() const { const std::vector<TypedValue> &
TypedValue::Value<std::vector<TypedValue>>() const {
if (type_ != TypedValue::Type::List) { if (type_ != TypedValue::Type::List) {
throw TypedValueException("Incompatible template param and type"); throw TypedValueException("Incompatible template param and type");
} }
@ -102,7 +99,7 @@ std::vector<TypedValue> TypedValue::Value<std::vector<TypedValue>>() const {
} }
template <> template <>
std::map<std::string, TypedValue> std::map<std::string, TypedValue> const &
TypedValue::Value<std::map<std::string, TypedValue>>() const { TypedValue::Value<std::map<std::string, TypedValue>>() const {
if (type_ != TypedValue::Type::Map) { if (type_ != TypedValue::Type::Map) {
throw TypedValueException("Incompatible template param and type"); throw TypedValueException("Incompatible template param and type");
@ -110,159 +107,222 @@ TypedValue::Value<std::map<std::string, TypedValue>>() const {
return map_v; return map_v;
} }
template <> template <> const VertexAccessor &TypedValue::Value<VertexAccessor>() const {
VertexAccessor TypedValue::Value<VertexAccessor>() const {
if (type_ != TypedValue::Type::Vertex) { if (type_ != TypedValue::Type::Vertex) {
throw TypedValueException("Incompatible template param and type"); throw TypedValueException("Incompatible template param and type");
} }
return vertex_v; return vertex_v;
} }
template <> template <> const EdgeAccessor &TypedValue::Value<EdgeAccessor>() const {
EdgeAccessor TypedValue::Value<EdgeAccessor>() const {
if (type_ != TypedValue::Type::Edge) { if (type_ != TypedValue::Type::Edge) {
throw TypedValueException("Incompatible template param and type"); throw TypedValueException("Incompatible template param and type");
} }
return edge_v; return edge_v;
} }
template <> template <> const Path &TypedValue::Value<Path>() const {
Path TypedValue::Value<Path>() const {
if (type_ != TypedValue::Type::Path) { if (type_ != TypedValue::Type::Path) {
throw TypedValueException("Incompatible template param and type"); throw TypedValueException("Incompatible template param and type");
} }
return path_v; return path_v;
} }
TypedValue::TypedValue(const TypedValue& other) : type_(other.type_) { template <> bool &TypedValue::Value<bool>() {
if (type_ != TypedValue::Type::Bool) {
throw TypedValueException("Incompatible template param and type");
}
return bool_v;
}
template <> int64_t &TypedValue::Value<int64_t>() {
if (type_ != TypedValue::Type::Int) {
throw TypedValueException("Incompatible template param and type");
}
return int_v;
}
template <> double &TypedValue::Value<double>() {
if (type_ != TypedValue::Type::Double) {
throw TypedValueException("Incompatible template param and type");
}
return double_v;
}
template <> std::string &TypedValue::Value<std::string>() {
if (type_ != TypedValue::Type::String) {
throw TypedValueException("Incompatible template param and type");
}
return string_v;
}
template <>
std::vector<TypedValue> &TypedValue::Value<std::vector<TypedValue>>() {
if (type_ != TypedValue::Type::List) {
throw TypedValueException("Incompatible template param and type");
}
return list_v;
}
template <>
std::map<std::string, TypedValue> &
TypedValue::Value<std::map<std::string, TypedValue>>() {
if (type_ != TypedValue::Type::Map) {
throw TypedValueException("Incompatible template param and type");
}
return map_v;
}
template <> VertexAccessor &TypedValue::Value<VertexAccessor>() {
if (type_ != TypedValue::Type::Vertex) {
throw TypedValueException("Incompatible template param and type");
}
return vertex_v;
}
template <> EdgeAccessor &TypedValue::Value<EdgeAccessor>() {
if (type_ != TypedValue::Type::Edge) {
throw TypedValueException("Incompatible template param and type");
}
return edge_v;
}
template <> Path &TypedValue::Value<Path>() {
if (type_ != TypedValue::Type::Path) {
throw TypedValueException("Incompatible template param and type");
}
return path_v;
}
TypedValue::TypedValue(const TypedValue &other) : type_(other.type_) {
switch (other.type_) { switch (other.type_) {
case TypedValue::Type::Null: case TypedValue::Type::Null:
return; return;
case TypedValue::Type::Bool: case TypedValue::Type::Bool:
this->bool_v = other.bool_v; this->bool_v = other.bool_v;
return; return;
case Type::Int: case Type::Int:
this->int_v = other.int_v; this->int_v = other.int_v;
return; return;
case Type::Double: case Type::Double:
this->double_v = other.double_v; this->double_v = other.double_v;
return; return;
case TypedValue::Type::String: case TypedValue::Type::String:
new (&string_v) std::string(other.string_v); new (&string_v) std::string(other.string_v);
return; return;
case Type::List: case Type::List:
new (&list_v) std::vector<TypedValue>(other.list_v); new (&list_v) std::vector<TypedValue>(other.list_v);
return; return;
case Type::Map: case Type::Map:
new (&map_v) std::map<std::string, TypedValue>(other.map_v); new (&map_v) std::map<std::string, TypedValue>(other.map_v);
return; return;
case Type::Vertex: case Type::Vertex:
new (&vertex_v) VertexAccessor(other.vertex_v); new (&vertex_v) VertexAccessor(other.vertex_v);
return; return;
case Type::Edge: case Type::Edge:
new (&edge_v) EdgeAccessor(other.edge_v); new (&edge_v) EdgeAccessor(other.edge_v);
return; return;
case Type::Path: case Type::Path:
new (&path_v) Path(other.path_v); new (&path_v) Path(other.path_v);
} }
permanent_fail("Unsupported TypedValue::Type"); permanent_fail("Unsupported TypedValue::Type");
} }
std::ostream& operator<<(std::ostream& os, const TypedValue::Type type) { std::ostream &operator<<(std::ostream &os, const TypedValue::Type type) {
switch (type) { switch (type) {
case TypedValue::Type::Null: case TypedValue::Type::Null:
return os << "null"; return os << "null";
case TypedValue::Type::Bool: case TypedValue::Type::Bool:
return os << "bool"; return os << "bool";
case TypedValue::Type::Int: case TypedValue::Type::Int:
return os << "int"; return os << "int";
case TypedValue::Type::Double: case TypedValue::Type::Double:
return os << "double"; return os << "double";
case TypedValue::Type::String: case TypedValue::Type::String:
return os << "string"; return os << "string";
case TypedValue::Type::List: case TypedValue::Type::List:
return os << "list"; return os << "list";
case TypedValue::Type::Map: case TypedValue::Type::Map:
return os << "map"; return os << "map";
case TypedValue::Type::Vertex: case TypedValue::Type::Vertex:
return os << "vertex"; return os << "vertex";
case TypedValue::Type::Edge: case TypedValue::Type::Edge:
return os << "edge"; return os << "edge";
case TypedValue::Type::Path: case TypedValue::Type::Path:
return os << "path"; return os << "path";
} }
permanent_fail("Unsupported TypedValue::Type"); permanent_fail("Unsupported TypedValue::Type");
} }
std::ostream& operator<<(std::ostream& os, const TypedValue& value) { std::ostream &operator<<(std::ostream &os, const TypedValue &value) {
switch (value.type_) { switch (value.type_) {
case TypedValue::Type::Null: case TypedValue::Type::Null:
return os << "Null"; return os << "Null";
case TypedValue::Type::Bool: case TypedValue::Type::Bool:
return os << (value.Value<bool>() ? "true" : "false"); return os << (value.Value<bool>() ? "true" : "false");
case TypedValue::Type::Int: case TypedValue::Type::Int:
return os << value.Value<int64_t>(); return os << value.Value<int64_t>();
case TypedValue::Type::Double: case TypedValue::Type::Double:
return os << value.Value<double>(); return os << value.Value<double>();
case TypedValue::Type::String: case TypedValue::Type::String:
return os << value.Value<std::string>(); return os << value.Value<std::string>();
case TypedValue::Type::List: case TypedValue::Type::List:
os << "["; os << "[";
for (const auto& x : value.Value<std::vector<TypedValue>>()) { for (const auto &x : value.Value<std::vector<TypedValue>>()) {
os << x << ","; os << x << ",";
} }
return os << "]"; return os << "]";
case TypedValue::Type::Map: case TypedValue::Type::Map:
os << "{"; os << "{";
for (const auto& x : value.Value<std::map<std::string, TypedValue>>()) { for (const auto &x : value.Value<std::map<std::string, TypedValue>>()) {
os << x.first << ": " << x.second << ","; os << x.first << ": " << x.second << ",";
} }
return os << "}"; return os << "}";
case TypedValue::Type::Vertex: case TypedValue::Type::Vertex:
return os << value.Value<VertexAccessor>(); return os << value.Value<VertexAccessor>();
case TypedValue::Type::Edge: case TypedValue::Type::Edge:
return os << value.Value<EdgeAccessor>(); return os << value.Value<EdgeAccessor>();
case TypedValue::Type::Path: case TypedValue::Type::Path:
return os << value.Value<Path>(); return os << value.Value<Path>();
} }
permanent_fail("Unsupported PropertyValue::Type"); permanent_fail("Unsupported PropertyValue::Type");
} }
TypedValue& TypedValue::operator=(const TypedValue& other) { TypedValue &TypedValue::operator=(const TypedValue &other) {
// set the type of this // set the type of this
this->~TypedValue(); this->~TypedValue();
type_ = other.type_; type_ = other.type_;
if (this != &other) { if (this != &other) {
switch (other.type_) { switch (other.type_) {
case TypedValue::Type::Null: case TypedValue::Type::Null:
case TypedValue::Type::Bool: case TypedValue::Type::Bool:
this->bool_v = other.bool_v; this->bool_v = other.bool_v;
return *this; return *this;
case TypedValue::Type::Int: case TypedValue::Type::Int:
this->int_v = other.int_v; this->int_v = other.int_v;
return *this; return *this;
case TypedValue::Type::Double: case TypedValue::Type::Double:
this->double_v = other.double_v; this->double_v = other.double_v;
return *this; return *this;
case TypedValue::Type::String: case TypedValue::Type::String:
new (&string_v) std::string(other.string_v); new (&string_v) std::string(other.string_v);
return *this; return *this;
case TypedValue::Type::List: case TypedValue::Type::List:
new (&list_v) std::vector<TypedValue>(other.list_v); new (&list_v) std::vector<TypedValue>(other.list_v);
return *this; return *this;
case TypedValue::Type::Map: case TypedValue::Type::Map:
new (&map_v) std::map<std::string, TypedValue>(other.map_v); new (&map_v) std::map<std::string, TypedValue>(other.map_v);
return *this; return *this;
case TypedValue::Type::Vertex: case TypedValue::Type::Vertex:
new (&vertex_v) VertexAccessor(other.vertex_v); new (&vertex_v) VertexAccessor(other.vertex_v);
return *this; return *this;
case TypedValue::Type::Edge: case TypedValue::Type::Edge:
new (&edge_v) EdgeAccessor(other.edge_v); new (&edge_v) EdgeAccessor(other.edge_v);
return *this; return *this;
case TypedValue::Type::Path: case TypedValue::Type::Path:
new (&path_v) Path(other.path_v); new (&path_v) Path(other.path_v);
return *this; return *this;
} }
} }
permanent_fail("Unsupported TypedValue::Type"); permanent_fail("Unsupported TypedValue::Type");
@ -272,38 +332,38 @@ const TypedValue TypedValue::Null = TypedValue();
TypedValue::~TypedValue() { TypedValue::~TypedValue() {
switch (type_) { switch (type_) {
// destructor for primitive types does nothing // destructor for primitive types does nothing
case Type::Null: case Type::Null:
case Type::Bool: case Type::Bool:
case Type::Int: case Type::Int:
case Type::Double: case Type::Double:
return; return;
// we need to call destructors for non primitive types since we used // we need to call destructors for non primitive types since we used
// placement new // placement new
case Type::String: case Type::String:
// Clang fails to compile ~std::string. It seems it is a bug in some // Clang fails to compile ~std::string. It seems it is a bug in some
// versions of clang. using namespace std statement solves the issue. // versions of clang. using namespace std statement solves the issue.
using namespace std; using namespace std;
string_v.~string(); string_v.~string();
return; return;
case Type::List: case Type::List:
using namespace std; using namespace std;
list_v.~vector<TypedValue>(); list_v.~vector<TypedValue>();
return; return;
case Type::Map: case Type::Map:
using namespace std; using namespace std;
map_v.~map<std::string, TypedValue>(); map_v.~map<std::string, TypedValue>();
return; return;
case Type::Vertex: case Type::Vertex:
vertex_v.~VertexAccessor(); vertex_v.~VertexAccessor();
return; return;
case Type::Edge: case Type::Edge:
edge_v.~EdgeAccessor(); edge_v.~EdgeAccessor();
return; return;
case Type::Path: case Type::Path:
path_v.~Path(); path_v.~Path();
return; return;
} }
permanent_fail("Unsupported TypedValue::Type"); permanent_fail("Unsupported TypedValue::Type");
} }
@ -315,19 +375,19 @@ TypedValue::~TypedValue() {
* @param value * @param value
* @return * @return
*/ */
double ToDouble(const TypedValue& value) { double ToDouble(const TypedValue &value) {
switch (value.type()) { switch (value.type()) {
case TypedValue::Type::Int: case TypedValue::Type::Int:
return (double)value.Value<int64_t>(); return (double)value.Value<int64_t>();
case TypedValue::Type::Double: case TypedValue::Type::Double:
return value.Value<double>(); return value.Value<double>();
default: default:
throw TypedValueException( throw TypedValueException(
"Unsupported TypedValue::Type conversion to double"); "Unsupported TypedValue::Type conversion to double");
} }
} }
TypedValue operator<(const TypedValue& a, const TypedValue& b) { TypedValue operator<(const TypedValue &a, const TypedValue &b) {
if (a.type() == TypedValue::Type::Bool || b.type() == TypedValue::Type::Bool) if (a.type() == TypedValue::Type::Bool || b.type() == TypedValue::Type::Bool)
throw TypedValueException("Invalid 'less' operand types({} + {})", a.type(), throw TypedValueException("Invalid 'less' operand types({} + {})", a.type(),
b.type()); b.type());
@ -356,7 +416,7 @@ TypedValue operator<(const TypedValue& a, const TypedValue& b) {
// TODO: 2 = "2" -> false, I don't think this is handled correctly at the // TODO: 2 = "2" -> false, I don't think this is handled correctly at the
// moment. // moment.
TypedValue operator==(const TypedValue& a, const TypedValue& b) { TypedValue operator==(const TypedValue &a, const TypedValue &b) {
if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null) if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null)
return TypedValue::Null; return TypedValue::Null;
@ -370,7 +430,8 @@ TypedValue operator==(const TypedValue& a, const TypedValue& b) {
// can compare list_v-s directly. // can compare list_v-s directly.
auto list1 = a.Value<std::vector<TypedValue>>(); auto list1 = a.Value<std::vector<TypedValue>>();
auto list2 = b.Value<std::vector<TypedValue>>(); auto list2 = b.Value<std::vector<TypedValue>>();
if (list1.size() != list2.size()) return false; if (list1.size() != list2.size())
return false;
for (int i = 0; i < (int)list1.size(); ++i) { for (int i = 0; i < (int)list1.size(); ++i) {
if (!(list1[i] == list2[i]).Value<bool>()) { if (!(list1[i] == list2[i]).Value<bool>()) {
return false; return false;
@ -417,15 +478,15 @@ TypedValue operator==(const TypedValue& a, const TypedValue& b) {
} }
} }
TypedValue operator!(const TypedValue& a) { TypedValue operator!(const TypedValue &a) {
switch (a.type()) { switch (a.type()) {
case TypedValue::Type::Null: case TypedValue::Type::Null:
return TypedValue::Null; return TypedValue::Null;
case TypedValue::Type::Bool: case TypedValue::Type::Bool:
return TypedValue(!a.Value<bool>()); return TypedValue(!a.Value<bool>());
default: default:
throw TypedValueException("Invalid logical not operand type (!{})", throw TypedValueException("Invalid logical not operand type (!{})",
a.type()); a.type());
} }
} }
@ -435,32 +496,32 @@ TypedValue operator!(const TypedValue& a) {
* @param value a value. * @param value a value.
* @return A string. * @return A string.
*/ */
std::string ValueToString(const TypedValue& value) { std::string ValueToString(const TypedValue &value) {
switch (value.type()) { switch (value.type()) {
case TypedValue::Type::String: case TypedValue::Type::String:
return value.Value<std::string>(); return value.Value<std::string>();
case TypedValue::Type::Int: case TypedValue::Type::Int:
return std::to_string(value.Value<int64_t>()); return std::to_string(value.Value<int64_t>());
case TypedValue::Type::Double: case TypedValue::Type::Double:
return fmt::format("{}", value.Value<double>()); return fmt::format("{}", value.Value<double>());
// unsupported situations // unsupported situations
default: default:
throw TypedValueException( throw TypedValueException(
"Unsupported TypedValue::Type conversion to string"); "Unsupported TypedValue::Type conversion to string");
} }
} }
TypedValue operator-(const TypedValue& a) { TypedValue operator-(const TypedValue &a) {
switch (a.type()) { switch (a.type()) {
case TypedValue::Type::Null: case TypedValue::Type::Null:
return TypedValue::Null; return TypedValue::Null;
case TypedValue::Type::Int: case TypedValue::Type::Int:
return -a.Value<int64_t>(); return -a.Value<int64_t>();
case TypedValue::Type::Double: case TypedValue::Type::Double:
return -a.Value<double>(); return -a.Value<double>();
default: default:
throw TypedValueException("Invalid unary minus operand type (-{})", throw TypedValueException("Invalid unary minus operand type (-{})",
a.type()); a.type());
} }
} }
@ -475,13 +536,14 @@ TypedValue operator-(const TypedValue& a) {
* @param op_name Name of the operation, used only for exception description, * @param op_name Name of the operation, used only for exception description,
* if raised. * if raised.
*/ */
inline void EnsureArithmeticallyOk(const TypedValue& a, const TypedValue& b, inline void EnsureArithmeticallyOk(const TypedValue &a, const TypedValue &b,
bool string_ok, const std::string& op_name) { bool string_ok, const std::string &op_name) {
if (a.type() == TypedValue::Type::Bool || b.type() == TypedValue::Type::Bool) if (a.type() == TypedValue::Type::Bool || b.type() == TypedValue::Type::Bool)
throw TypedValueException("Invalid {} operand types {}, {}", op_name, throw TypedValueException("Invalid {} operand types {}, {}", op_name,
a.type(), b.type()); a.type(), b.type());
if (string_ok) return; if (string_ok)
return;
if (a.type() == TypedValue::Type::String || if (a.type() == TypedValue::Type::String ||
b.type() == TypedValue::Type::String) b.type() == TypedValue::Type::String)
@ -489,14 +551,14 @@ inline void EnsureArithmeticallyOk(const TypedValue& a, const TypedValue& b,
a.type(), b.type()); a.type(), b.type());
} }
TypedValue operator+(const TypedValue& a, const TypedValue& b) { TypedValue operator+(const TypedValue &a, const TypedValue &b) {
if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null) if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null)
return TypedValue::Null; return TypedValue::Null;
if (a.type() == TypedValue::Type::List || if (a.type() == TypedValue::Type::List ||
b.type() == TypedValue::Type::List) { b.type() == TypedValue::Type::List) {
std::vector<TypedValue> list; std::vector<TypedValue> list;
auto append_list = [&list](const TypedValue& v) { auto append_list = [&list](const TypedValue &v) {
if (v.type() == TypedValue::Type::List) { if (v.type() == TypedValue::Type::List) {
auto list2 = v.Value<std::vector<TypedValue>>(); auto list2 = v.Value<std::vector<TypedValue>>();
list.insert(list.end(), list2.begin(), list2.end()); list.insert(list.end(), list2.begin(), list2.end());
@ -525,7 +587,7 @@ TypedValue operator+(const TypedValue& a, const TypedValue& b) {
} }
} }
TypedValue operator-(const TypedValue& a, const TypedValue& b) { TypedValue operator-(const TypedValue &a, const TypedValue &b) {
EnsureArithmeticallyOk(a, b, false, "subtraction"); EnsureArithmeticallyOk(a, b, false, "subtraction");
if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null) if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null)
@ -540,7 +602,7 @@ TypedValue operator-(const TypedValue& a, const TypedValue& b) {
} }
} }
TypedValue operator/(const TypedValue& a, const TypedValue& b) { TypedValue operator/(const TypedValue &a, const TypedValue &b) {
EnsureArithmeticallyOk(a, b, false, "division"); EnsureArithmeticallyOk(a, b, false, "division");
if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null) if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null)
@ -555,7 +617,7 @@ TypedValue operator/(const TypedValue& a, const TypedValue& b) {
} }
} }
TypedValue operator*(const TypedValue& a, const TypedValue& b) { TypedValue operator*(const TypedValue &a, const TypedValue &b) {
EnsureArithmeticallyOk(a, b, false, "multiplication"); EnsureArithmeticallyOk(a, b, false, "multiplication");
if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null) if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null)
@ -570,7 +632,7 @@ TypedValue operator*(const TypedValue& a, const TypedValue& b) {
} }
} }
TypedValue operator%(const TypedValue& a, const TypedValue& b) { TypedValue operator%(const TypedValue &a, const TypedValue &b) {
EnsureArithmeticallyOk(a, b, false, "modulo"); EnsureArithmeticallyOk(a, b, false, "modulo");
if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null) if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null)
@ -585,13 +647,13 @@ TypedValue operator%(const TypedValue& a, const TypedValue& b) {
} }
} }
inline bool IsLogicallyOk(const TypedValue& a) { inline bool IsLogicallyOk(const TypedValue &a) {
return a.type() == TypedValue::Type::Bool || return a.type() == TypedValue::Type::Bool ||
a.type() == TypedValue::Type::Null; a.type() == TypedValue::Type::Null;
} }
// TODO: Fix bugs in && and ||. null or true -> true; false and null -> false // TODO: Fix bugs in && and ||. null or true -> true; false and null -> false
TypedValue operator&&(const TypedValue& a, const TypedValue& b) { TypedValue operator&&(const TypedValue &a, const TypedValue &b) {
if (IsLogicallyOk(a) && IsLogicallyOk(b)) { if (IsLogicallyOk(a) && IsLogicallyOk(b)) {
if (a.type() == TypedValue::Type::Null || if (a.type() == TypedValue::Type::Null ||
b.type() == TypedValue::Type::Null) { b.type() == TypedValue::Type::Null) {
@ -605,7 +667,7 @@ TypedValue operator&&(const TypedValue& a, const TypedValue& b) {
} }
} }
TypedValue operator||(const TypedValue& a, const TypedValue& b) { TypedValue operator||(const TypedValue &a, const TypedValue &b) {
if (IsLogicallyOk(a) && IsLogicallyOk(b)) { if (IsLogicallyOk(a) && IsLogicallyOk(b)) {
if (a.type() == TypedValue::Type::Null || if (a.type() == TypedValue::Type::Null ||
b.type() == TypedValue::Type::Null) { b.type() == TypedValue::Type::Null) {
@ -619,7 +681,7 @@ TypedValue operator||(const TypedValue& a, const TypedValue& b) {
} }
} }
TypedValue operator^(const TypedValue& a, const TypedValue& b) { TypedValue operator^(const TypedValue &a, const TypedValue &b) {
if (IsLogicallyOk(a) && IsLogicallyOk(b)) { if (IsLogicallyOk(a) && IsLogicallyOk(b)) {
if (a.type() == TypedValue::Type::Null || if (a.type() == TypedValue::Type::Null ||
b.type() == TypedValue::Type::Null) { b.type() == TypedValue::Type::Null) {

View File

@ -1,19 +1,19 @@
#pragma once #pragma once
#include <cstdint>
#include <iostream> #include <iostream>
#include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include <map>
#include <cstdint>
#include "storage/edge_accessor.hpp"
#include "storage/property_value.hpp"
#include "storage/vertex_accessor.hpp"
#include "traversal/path.hpp"
#include "utils/exceptions/stacktrace_exception.hpp" #include "utils/exceptions/stacktrace_exception.hpp"
#include "utils/total_ordering.hpp" #include "utils/total_ordering.hpp"
#include "utils/underlying_cast.hpp" #include "utils/underlying_cast.hpp"
#include "storage/property_value.hpp"
#include "storage/edge_accessor.hpp"
#include "storage/vertex_accessor.hpp"
#include "traversal/path.hpp"
typedef traversal_template::Path<VertexAccessor, EdgeAccessor> Path; typedef traversal_template::Path<VertexAccessor, EdgeAccessor> Path;
@ -26,11 +26,11 @@ typedef traversal_template::Path<VertexAccessor, EdgeAccessor> Path;
* TypedValue::Type. Each such type corresponds to exactly one C++ type. * TypedValue::Type. Each such type corresponds to exactly one C++ type.
*/ */
class TypedValue : public TotalOrdering<TypedValue, TypedValue, TypedValue> { class TypedValue : public TotalOrdering<TypedValue, TypedValue, TypedValue> {
public: public:
/** Private default constructor, makes Null */ /** Private default constructor, makes Null */
TypedValue() : type_(Type::Null) {} TypedValue() : type_(Type::Null) {}
public: public:
/** A value type. Each type corresponds to exactly one C++ type */ /** A value type. Each type corresponds to exactly one C++ type */
enum class Type : unsigned { enum class Type : unsigned {
Null, Null,
@ -58,32 +58,32 @@ class TypedValue : public TotalOrdering<TypedValue, TypedValue, TypedValue> {
operator PropertyValue() const; operator PropertyValue() const;
/// constructors for non-primitive types /// constructors for non-primitive types
TypedValue(const std::string& value) : type_(Type::String) { TypedValue(const std::string &value) : type_(Type::String) {
new (&string_v) std::string(value); new (&string_v) std::string(value);
} }
TypedValue(const char* value) : type_(Type::String) { TypedValue(const char *value) : type_(Type::String) {
new (&string_v) std::string(value); new (&string_v) std::string(value);
} }
TypedValue(const std::vector<TypedValue>& value) : type_(Type::List) { TypedValue(const std::vector<TypedValue> &value) : type_(Type::List) {
new (&list_v) std::vector<TypedValue>(value); new (&list_v) std::vector<TypedValue>(value);
} }
TypedValue(const std::map<std::string, TypedValue>& value) TypedValue(const std::map<std::string, TypedValue> &value)
: type_(Type::Map) { : type_(Type::Map) {
new (&map_v) std::map<std::string, TypedValue>(value); new (&map_v) std::map<std::string, TypedValue>(value);
} }
TypedValue(const VertexAccessor& vertex) : type_(Type::Vertex) { TypedValue(const VertexAccessor &vertex) : type_(Type::Vertex) {
new (&vertex_v) VertexAccessor(vertex); new (&vertex_v) VertexAccessor(vertex);
} }
TypedValue(const EdgeAccessor& edge) : type_(Type::Edge) { TypedValue(const EdgeAccessor &edge) : type_(Type::Edge) {
new (&edge_v) EdgeAccessor(edge); new (&edge_v) EdgeAccessor(edge);
} }
TypedValue(const Path& path) : type_(Type::Path) { new (&path_v) Path(path); } TypedValue(const Path &path) : type_(Type::Path) { new (&path_v) Path(path); }
TypedValue(const PropertyValue& value); TypedValue(const PropertyValue &value);
// assignment ops // assignment ops
TypedValue& operator=(const TypedValue& other); TypedValue &operator=(const TypedValue &other);
TypedValue(const TypedValue& other); TypedValue(const TypedValue &other);
~TypedValue(); ~TypedValue();
Type type() const { return type_; } Type type() const { return type_; }
@ -95,12 +95,12 @@ class TypedValue : public TotalOrdering<TypedValue, TypedValue, TypedValue> {
* @tparam T Type to interpret the value as. * @tparam T Type to interpret the value as.
* @return The value as type T. * @return The value as type T.
*/ */
template <typename T> template <typename T> T &Value();
T Value() const; template <typename T> const T &Value() const;
friend std::ostream& operator<<(std::ostream& stream, const TypedValue&prop); friend std::ostream &operator<<(std::ostream &stream, const TypedValue &prop);
private: private:
// storage for the value of the property // storage for the value of the property
union { union {
bool bool_v; bool bool_v;
@ -133,31 +133,31 @@ class TypedValue : public TotalOrdering<TypedValue, TypedValue, TypedValue> {
* of incompatible Types. * of incompatible Types.
*/ */
class TypedValueException : public StacktraceException { class TypedValueException : public StacktraceException {
public: public:
using ::StacktraceException::StacktraceException; using ::StacktraceException::StacktraceException;
}; };
// comparison operators // comparison operators
// they return TypedValue because Null can be returned // they return TypedValue because Null can be returned
TypedValue operator==(const TypedValue& a, const TypedValue& b); TypedValue operator==(const TypedValue &a, const TypedValue &b);
TypedValue operator<(const TypedValue& a, const TypedValue& b); TypedValue operator<(const TypedValue &a, const TypedValue &b);
TypedValue operator!(const TypedValue& a); TypedValue operator!(const TypedValue &a);
// arithmetic operators // arithmetic operators
TypedValue operator-(const TypedValue& a); TypedValue operator-(const TypedValue &a);
TypedValue operator+(const TypedValue& a, const TypedValue& b); TypedValue operator+(const TypedValue &a, const TypedValue &b);
TypedValue operator-(const TypedValue& a, const TypedValue& b); TypedValue operator-(const TypedValue &a, const TypedValue &b);
TypedValue operator/(const TypedValue& a, const TypedValue& b); TypedValue operator/(const TypedValue &a, const TypedValue &b);
TypedValue operator*(const TypedValue& a, const TypedValue& b); TypedValue operator*(const TypedValue &a, const TypedValue &b);
TypedValue operator%(const TypedValue& a, const TypedValue& b); TypedValue operator%(const TypedValue &a, const TypedValue &b);
// binary bool operators // binary bool operators
TypedValue operator&&(const TypedValue& a, const TypedValue& b); TypedValue operator&&(const TypedValue &a, const TypedValue &b);
TypedValue operator||(const TypedValue& a, const TypedValue& b); TypedValue operator||(const TypedValue &a, const TypedValue &b);
// binary bool xor, not power operator // binary bool xor, not power operator
// Be careful: since ^ is binary operator and || and && are logical operators // Be careful: since ^ is binary operator and || and && are logical operators
// they have different priority in c++. // they have different priority in c++.
TypedValue operator^(const TypedValue& a, const TypedValue& b); TypedValue operator^(const TypedValue &a, const TypedValue &b);
// stream output // stream output
std::ostream& operator<<(std::ostream& os, const TypedValue::Type type); std::ostream &operator<<(std::ostream &os, const TypedValue::Type type);