Refactor PropertyValue

Reviewers: teon.banek, msantl

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D1654
This commit is contained in:
Matej Ferencevic 2018-10-12 10:06:20 +02:00
parent 4b5c0d3426
commit b527b2b4e4
3 changed files with 174 additions and 139 deletions

View File

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

View File

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

View File

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