Refactor PropertyValue
Reviewers: teon.banek, msantl Reviewed By: teon.banek Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1654
This commit is contained in:
parent
4b5c0d3426
commit
b527b2b4e4
src
@ -70,22 +70,19 @@ TypedValue::TypedValue(PropertyValue &&value) {
|
||||
break;
|
||||
case PropertyValue::Type::String:
|
||||
type_ = Type::String;
|
||||
// TODO: std::move() when PropertyValue is fixed
|
||||
new (&string_v) std::string(value.Value<std::string>());
|
||||
new (&string_v) std::string(std::move(value.Value<std::string>()));
|
||||
break;
|
||||
case PropertyValue::Type::List: {
|
||||
// TODO: std::move() when PropertyValue is fixed
|
||||
type_ = Type::List;
|
||||
auto vec = value.Value<std::vector<PropertyValue>>();
|
||||
auto &vec = value.Value<std::vector<PropertyValue>>();
|
||||
new (&list_v)
|
||||
std::vector<TypedValue>(std::make_move_iterator(vec.begin()),
|
||||
std::make_move_iterator(vec.end()));
|
||||
break;
|
||||
}
|
||||
case PropertyValue::Type::Map: {
|
||||
// TODO: std::move() when PropertyValue is fixed
|
||||
type_ = Type::Map;
|
||||
auto map = value.Value<std::map<std::string, PropertyValue>>();
|
||||
auto &map = value.Value<std::map<std::string, PropertyValue>>();
|
||||
new (&map_v) std::map<std::string, TypedValue>(
|
||||
std::make_move_iterator(map.begin()),
|
||||
std::make_move_iterator(map.end()));
|
||||
|
@ -1,133 +1,155 @@
|
||||
#include "storage/common/property_value.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "glog/logging.h"
|
||||
|
||||
// Value extraction template instantiations
|
||||
// const value extraction template instantiations
|
||||
template <>
|
||||
bool PropertyValue::Value<bool>() const {
|
||||
if (type_ != PropertyValue::Type::Bool) {
|
||||
const bool &PropertyValue::Value<bool>() const {
|
||||
if (type_ != Type::Bool) {
|
||||
throw PropertyValueException("Incompatible template param and type");
|
||||
}
|
||||
return bool_v;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string PropertyValue::Value<std::string>() const {
|
||||
if (type_ != PropertyValue::Type::String) {
|
||||
throw PropertyValueException("Incompatible template param and type");
|
||||
}
|
||||
return *string_v;
|
||||
}
|
||||
|
||||
template <>
|
||||
int64_t PropertyValue::Value<int64_t>() const {
|
||||
if (type_ != PropertyValue::Type::Int) {
|
||||
const int64_t &PropertyValue::Value<int64_t>() const {
|
||||
if (type_ != Type::Int) {
|
||||
throw PropertyValueException("Incompatible template param and type");
|
||||
}
|
||||
return int_v;
|
||||
}
|
||||
|
||||
template <>
|
||||
double PropertyValue::Value<double>() const {
|
||||
if (type_ != PropertyValue::Type::Double) {
|
||||
const double &PropertyValue::Value<double>() const {
|
||||
if (type_ != Type::Double) {
|
||||
throw PropertyValueException("Incompatible template param and type");
|
||||
}
|
||||
return double_v;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::vector<PropertyValue> PropertyValue::Value<std::vector<PropertyValue>>()
|
||||
const {
|
||||
if (type_ != PropertyValue::Type::List) {
|
||||
const std::string &PropertyValue::Value<std::string>() const {
|
||||
if (type_ != Type::String) {
|
||||
throw PropertyValueException("Incompatible template param and type");
|
||||
}
|
||||
return *list_v;
|
||||
return string_v;
|
||||
}
|
||||
|
||||
template <>
|
||||
const std::vector<PropertyValue>
|
||||
&PropertyValue::Value<std::vector<PropertyValue>>() const {
|
||||
if (type_ != Type::List) {
|
||||
throw PropertyValueException("Incompatible template param and type");
|
||||
}
|
||||
return list_v;
|
||||
}
|
||||
|
||||
template <>
|
||||
const std::map<std::string, PropertyValue>
|
||||
&PropertyValue::Value<std::map<std::string, PropertyValue>>() const {
|
||||
if (type_ != Type::Map) {
|
||||
throw PropertyValueException("Incompatible template param and type");
|
||||
}
|
||||
return map_v;
|
||||
}
|
||||
|
||||
// value extraction template instantiations
|
||||
template <>
|
||||
bool &PropertyValue::Value<bool>() {
|
||||
if (type_ != Type::Bool) {
|
||||
throw PropertyValueException("Incompatible template param and type");
|
||||
}
|
||||
return bool_v;
|
||||
}
|
||||
|
||||
template <>
|
||||
int64_t &PropertyValue::Value<int64_t>() {
|
||||
if (type_ != Type::Int) {
|
||||
throw PropertyValueException("Incompatible template param and type");
|
||||
}
|
||||
return int_v;
|
||||
}
|
||||
|
||||
template <>
|
||||
double &PropertyValue::Value<double>() {
|
||||
if (type_ != Type::Double) {
|
||||
throw PropertyValueException("Incompatible template param and type");
|
||||
}
|
||||
return double_v;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string &PropertyValue::Value<std::string>() {
|
||||
if (type_ != Type::String) {
|
||||
throw PropertyValueException("Incompatible template param and type");
|
||||
}
|
||||
return string_v;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::vector<PropertyValue> &PropertyValue::Value<std::vector<PropertyValue>>() {
|
||||
if (type_ != Type::List) {
|
||||
throw PropertyValueException("Incompatible template param and type");
|
||||
}
|
||||
return list_v;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::map<std::string, PropertyValue>
|
||||
PropertyValue::Value<std::map<std::string, PropertyValue>>() const {
|
||||
if (type_ != PropertyValue::Type::Map) {
|
||||
&PropertyValue::Value<std::map<std::string, PropertyValue>>() {
|
||||
if (type_ != Type::Map) {
|
||||
throw PropertyValueException("Incompatible template param and type");
|
||||
}
|
||||
return *map_v;
|
||||
return map_v;
|
||||
}
|
||||
|
||||
// constructors
|
||||
PropertyValue::PropertyValue(const PropertyValue &other) : type_(other.type_) {
|
||||
switch (other.type_) {
|
||||
case PropertyValue::Type::Null:
|
||||
case Type::Null:
|
||||
return;
|
||||
|
||||
case PropertyValue::Type::Bool:
|
||||
case Type::Bool:
|
||||
this->bool_v = other.bool_v;
|
||||
return;
|
||||
|
||||
case PropertyValue::Type::String:
|
||||
new (&string_v)
|
||||
std::unique_ptr<std::string>(new std::string(*other.string_v));
|
||||
return;
|
||||
|
||||
case Type::Int:
|
||||
this->int_v = other.int_v;
|
||||
return;
|
||||
|
||||
case Type::Double:
|
||||
this->double_v = other.double_v;
|
||||
return;
|
||||
|
||||
case Type::List:
|
||||
new (&list_v) std::unique_ptr<std::vector<PropertyValue>>(
|
||||
new std::vector<PropertyValue>(*other.list_v));
|
||||
case Type::String:
|
||||
new (&string_v) std::string(other.string_v);
|
||||
return;
|
||||
case Type::List:
|
||||
new (&list_v) std::vector<PropertyValue>(other.list_v);
|
||||
return;
|
||||
|
||||
case Type::Map:
|
||||
new (&map_v) std::unique_ptr<std::map<std::string, PropertyValue>>(
|
||||
new std::map<std::string, PropertyValue>(*other.map_v));
|
||||
new (&map_v) std::map<std::string, PropertyValue>(other.map_v);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(FATAL) << "Unsupported PropertyValue::Type";
|
||||
}
|
||||
|
||||
PropertyValue::PropertyValue(PropertyValue &&other) : type_(other.type_) {
|
||||
switch (other.type_) {
|
||||
case PropertyValue::Type::Null:
|
||||
case Type::Null:
|
||||
return;
|
||||
|
||||
case PropertyValue::Type::Bool:
|
||||
case Type::Bool:
|
||||
this->bool_v = other.bool_v;
|
||||
return;
|
||||
|
||||
case PropertyValue::Type::String:
|
||||
new (&string_v) std::unique_ptr<std::string>(std::move(other.string_v));
|
||||
return;
|
||||
|
||||
case Type::Int:
|
||||
this->int_v = other.int_v;
|
||||
return;
|
||||
|
||||
case Type::Double:
|
||||
this->double_v = other.double_v;
|
||||
return;
|
||||
|
||||
case Type::List:
|
||||
new (&list_v)
|
||||
std::unique_ptr<std::vector<PropertyValue>>(std::move(other.list_v));
|
||||
case Type::String:
|
||||
new (&string_v) std::string(std::move(other.string_v));
|
||||
return;
|
||||
case Type::List:
|
||||
new (&list_v) std::vector<PropertyValue>(std::move(other.list_v));
|
||||
return;
|
||||
|
||||
case Type::Map:
|
||||
new (&map_v) std::unique_ptr<std::map<std::string, PropertyValue>>(
|
||||
std::move(other.map_v));
|
||||
new (&map_v) std::map<std::string, PropertyValue>(std::move(other.map_v));
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(FATAL) << "Unsupported PropertyValue::Type";
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const PropertyValue::Type type) {
|
||||
@ -147,7 +169,6 @@ std::ostream &operator<<(std::ostream &os, const PropertyValue::Type type) {
|
||||
case PropertyValue::Type::Map:
|
||||
return os << "map";
|
||||
}
|
||||
LOG(FATAL) << "Unsupported PropertyValue::Type";
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const PropertyValue &value) {
|
||||
@ -176,77 +197,78 @@ std::ostream &operator<<(std::ostream &os, const PropertyValue &value) {
|
||||
}
|
||||
return os << "}";
|
||||
}
|
||||
LOG(FATAL) << "Unsupported PropertyValue::Type";
|
||||
}
|
||||
|
||||
PropertyValue &PropertyValue::operator=(const PropertyValue &other) {
|
||||
this->~PropertyValue();
|
||||
type_ = other.type_;
|
||||
|
||||
if (this != &other) {
|
||||
DestroyValue();
|
||||
type_ = other.type_;
|
||||
|
||||
switch (other.type_) {
|
||||
case PropertyValue::Type::Null:
|
||||
case PropertyValue::Type::Bool:
|
||||
case Type::Null:
|
||||
case Type::Bool:
|
||||
this->bool_v = other.bool_v;
|
||||
return *this;
|
||||
case PropertyValue::Type::String:
|
||||
new (&string_v)
|
||||
std::unique_ptr<std::string>(new std::string(*other.string_v));
|
||||
return *this;
|
||||
case PropertyValue::Type::Int:
|
||||
break;
|
||||
case Type::Int:
|
||||
this->int_v = other.int_v;
|
||||
return *this;
|
||||
case PropertyValue::Type::Double:
|
||||
break;
|
||||
case Type::Double:
|
||||
this->double_v = other.double_v;
|
||||
return *this;
|
||||
case PropertyValue::Type::List:
|
||||
new (&list_v) std::unique_ptr<std::vector<PropertyValue>>(
|
||||
new std::vector<PropertyValue>(*other.list_v));
|
||||
return *this;
|
||||
case PropertyValue::Type::Map:
|
||||
new (&map_v) std::unique_ptr<std::map<std::string, PropertyValue>>(
|
||||
new std::map<std::string, PropertyValue>(*other.map_v));
|
||||
return *this;
|
||||
break;
|
||||
case Type::String:
|
||||
new (&string_v) std::string(other.string_v);
|
||||
break;
|
||||
case Type::List:
|
||||
new (&list_v) std::vector<PropertyValue>(other.list_v);
|
||||
break;
|
||||
case Type::Map:
|
||||
new (&map_v) std::map<std::string, PropertyValue>(other.map_v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOG(FATAL) << "Unsupported PropertyValue::Type";
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
PropertyValue &PropertyValue::operator=(PropertyValue &&other) {
|
||||
this->~PropertyValue();
|
||||
type_ = other.type_;
|
||||
|
||||
if (this != &other) {
|
||||
DestroyValue();
|
||||
type_ = other.type_;
|
||||
|
||||
switch (other.type_) {
|
||||
case PropertyValue::Type::Null:
|
||||
case PropertyValue::Type::Bool:
|
||||
case Type::Null:
|
||||
break;
|
||||
case Type::Bool:
|
||||
this->bool_v = other.bool_v;
|
||||
return *this;
|
||||
case PropertyValue::Type::String:
|
||||
new (&string_v) std::unique_ptr<std::string>(std::move(other.string_v));
|
||||
return *this;
|
||||
case PropertyValue::Type::Int:
|
||||
break;
|
||||
case Type::Int:
|
||||
this->int_v = other.int_v;
|
||||
return *this;
|
||||
case PropertyValue::Type::Double:
|
||||
break;
|
||||
case Type::Double:
|
||||
this->double_v = other.double_v;
|
||||
return *this;
|
||||
case PropertyValue::Type::List:
|
||||
new (&list_v) std::unique_ptr<std::vector<PropertyValue>>(
|
||||
std::move(other.list_v));
|
||||
return *this;
|
||||
case PropertyValue::Type::Map:
|
||||
new (&map_v) std::unique_ptr<std::map<std::string, PropertyValue>>(
|
||||
std::move(other.map_v));
|
||||
return *this;
|
||||
break;
|
||||
case Type::String:
|
||||
new (&string_v) std::string(std::move(other.string_v));
|
||||
break;
|
||||
case Type::List:
|
||||
new (&list_v) std::vector<PropertyValue>(std::move(other.list_v));
|
||||
break;
|
||||
case Type::Map:
|
||||
new (&map_v)
|
||||
std::map<std::string, PropertyValue>(std::move(other.map_v));
|
||||
break;
|
||||
}
|
||||
|
||||
// reset the type of other
|
||||
other = PropertyValue::Null;
|
||||
}
|
||||
LOG(FATAL) << "Unsupported PropertyValue::Type";
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const PropertyValue PropertyValue::Null = PropertyValue();
|
||||
|
||||
PropertyValue::~PropertyValue() {
|
||||
void PropertyValue::DestroyValue() {
|
||||
switch (type_) {
|
||||
// destructor for primitive types does nothing
|
||||
case Type::Null:
|
||||
@ -255,16 +277,20 @@ PropertyValue::~PropertyValue() {
|
||||
case Type::Double:
|
||||
return;
|
||||
|
||||
// destructor for shared pointer must release
|
||||
// destructor for non primitive types since we used placement new
|
||||
case Type::String:
|
||||
string_v.~unique_ptr<std::string>();
|
||||
// Clang fails to compile ~std::string. It seems it is a bug in some
|
||||
// versions of clang. Using namespace std statement solves the issue.
|
||||
using namespace std;
|
||||
string_v.~string();
|
||||
return;
|
||||
case Type::List:
|
||||
list_v.~unique_ptr<std::vector<PropertyValue>>();
|
||||
list_v.~vector();
|
||||
return;
|
||||
case Type::Map:
|
||||
map_v.~unique_ptr<std::map<std::string, PropertyValue>>();
|
||||
map_v.~map();
|
||||
return;
|
||||
}
|
||||
LOG(FATAL) << "Unsupported PropertyValue::Type";
|
||||
}
|
||||
|
||||
PropertyValue::~PropertyValue() { DestroyValue(); }
|
||||
|
@ -2,12 +2,10 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/exceptions.hpp"
|
||||
#include "utils/total_ordering.hpp"
|
||||
|
||||
/**
|
||||
* Encapsulation of a value and its type in a class that has no compile-time
|
||||
@ -42,21 +40,31 @@ class PropertyValue {
|
||||
PropertyValue(int64_t value) : type_(Type::Int) { int_v = value; }
|
||||
PropertyValue(double value) : type_(Type::Double) { double_v = value; }
|
||||
|
||||
/// constructors for non-primitive types (shared pointers)
|
||||
// constructors for non-primitive types
|
||||
PropertyValue(const std::string &value) : type_(Type::String) {
|
||||
new (&string_v) std::unique_ptr<std::string>(new std::string(value));
|
||||
new (&string_v) std::string(value);
|
||||
}
|
||||
PropertyValue(const char *value) : type_(Type::String) {
|
||||
new (&string_v) std::unique_ptr<std::string>(new std::string(value));
|
||||
new (&string_v) std::string(value);
|
||||
}
|
||||
PropertyValue(const std::vector<PropertyValue> &value) : type_(Type::List) {
|
||||
new (&list_v) std::unique_ptr<std::vector<PropertyValue>>(
|
||||
new std::vector<PropertyValue>(value));
|
||||
new (&list_v) std::vector<PropertyValue>(value);
|
||||
}
|
||||
PropertyValue(const std::map<std::string, PropertyValue> &value)
|
||||
: type_(Type::Map) {
|
||||
new (&map_v) std::unique_ptr<std::map<std::string, PropertyValue>>(
|
||||
new std::map<std::string, PropertyValue>(value));
|
||||
new (&map_v) std::map<std::string, PropertyValue>(value);
|
||||
}
|
||||
|
||||
// move constructors for non-primitive types
|
||||
PropertyValue(std::string &&value) : type_(Type::String) {
|
||||
new (&string_v) std::string(std::move(value));
|
||||
}
|
||||
PropertyValue(std::vector<PropertyValue> &&value) : type_(Type::List) {
|
||||
new (&list_v) std::vector<PropertyValue>(std::move(value));
|
||||
}
|
||||
PropertyValue(std::map<std::string, PropertyValue> &&value)
|
||||
: type_(Type::Map) {
|
||||
new (&map_v) std::map<std::string, PropertyValue>(std::move(value));
|
||||
}
|
||||
|
||||
PropertyValue &operator=(const PropertyValue &other);
|
||||
@ -79,22 +87,26 @@ class PropertyValue {
|
||||
* @return The value as type T.
|
||||
*/
|
||||
template <typename T>
|
||||
T Value() const;
|
||||
const T &Value() const;
|
||||
template <typename T>
|
||||
T &Value();
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &stream,
|
||||
const PropertyValue &prop);
|
||||
|
||||
private:
|
||||
void DestroyValue();
|
||||
|
||||
// storage for the value of the property
|
||||
union {
|
||||
bool bool_v;
|
||||
int64_t int_v;
|
||||
double double_v;
|
||||
std::unique_ptr<std::string> string_v;
|
||||
std::string string_v;
|
||||
// We support lists of values of different types, neo4j supports lists of
|
||||
// values of the same type.
|
||||
std::unique_ptr<std::vector<PropertyValue>> list_v;
|
||||
std::unique_ptr<std::map<std::string, PropertyValue>> map_v;
|
||||
std::vector<PropertyValue> list_v;
|
||||
std::map<std::string, PropertyValue> map_v;
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user