PMR property value

This commit is contained in:
Antonio Andelic 2022-02-11 11:32:11 +01:00
parent 5aeaad198b
commit 49ad114366
15 changed files with 314 additions and 85 deletions

View File

@ -238,7 +238,7 @@ Value ToBoltValue(const storage::PropertyValue &value) {
case storage::PropertyValue::Type::Double:
return Value(value.ValueDouble());
case storage::PropertyValue::Type::String:
return Value(value.ValueString());
return Value(std::string{value.ValueString()});
case storage::PropertyValue::Type::List: {
const auto &values = value.ValueList();
std::vector<Value> vec;

View File

@ -25,6 +25,8 @@
#include <string_view>
#include <thread>
#include <jemalloc/jemalloc.h>
#include <fmt/format.h>
#include <gflags/gflags.h>
#include <spdlog/common.h>
@ -44,6 +46,7 @@
#include "query/procedure/py_module.hpp"
#include "requests/requests.hpp"
#include "storage/v2/isolation_level.hpp"
#include "storage/v2/property_value.hpp"
#include "storage/v2/storage.hpp"
#include "storage/v2/view.hpp"
#include "telemetry/telemetry.hpp"
@ -817,7 +820,7 @@ class BoltSession final : public communication::bolt::Session<communication::Inp
std::pair<std::vector<std::string>, std::optional<int>> Interpret(
const std::string &query, const std::map<std::string, communication::bolt::Value> &params) override {
std::map<std::string, storage::PropertyValue> params_pv;
storage::PropertyValue::TMap params_pv{utils::NewDeleteResource()};
for (const auto &kv : params) params_pv.emplace(kv.first, glue::ToPropertyValue(kv.second));
const std::string *username{nullptr};
if (user_) {

View File

@ -11,6 +11,9 @@
#include "query/cypher_query_interpreter.hpp"
#include "utils/memory.hpp"
#include "utils/pmr/string.hpp"
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
DEFINE_HIDDEN_bool(query_cost_planner, true, "Use the cost-estimating query planner.");
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
@ -20,7 +23,7 @@ DEFINE_VALIDATED_int32(query_plan_cache_ttl, 60, "Time to live for cached query
namespace query {
CachedPlan::CachedPlan(std::unique_ptr<LogicalPlan> plan) : plan_(std::move(plan)) {}
ParsedQuery ParseQuery(const std::string &query_string, const std::map<std::string, storage::PropertyValue> &params,
ParsedQuery ParseQuery(const std::string &query_string, const storage::PropertyValue::TMap &params,
utils::SkipList<QueryCacheEntry> *cache, utils::SpinLock *antlr_lock,
const InterpreterConfig::Query &query_config) {
// Strip the query for caching purposes. The process of stripping a query
@ -34,7 +37,7 @@ ParsedQuery ParseQuery(const std::string &query_string, const std::map<std::stri
// Check that all user-specified parameters are provided.
for (const auto &param_pair : stripped_query.parameters()) {
auto it = params.find(param_pair.second);
auto it = params.find(utils::pmr::string{param_pair.second, utils::NewDeleteResource()});
if (it == params.end()) {
throw query::UnprovidedParameterError("Parameter ${} not provided.", param_pair.second);

View File

@ -18,6 +18,7 @@
#include "query/frontend/semantic/symbol_generator.hpp"
#include "query/frontend/stripped.hpp"
#include "query/plan/planner.hpp"
#include "storage/v2/property_value.hpp"
#include "utils/flag_validation.hpp"
#include "utils/timer.hpp"
@ -101,7 +102,7 @@ struct PlanCacheEntry {
*/
struct ParsedQuery {
std::string query_string;
std::map<std::string, storage::PropertyValue> user_parameters;
storage::PropertyValue::TMap user_parameters;
Parameters parameters;
frontend::StrippedQuery stripped_query;
AstStorage ast_storage;
@ -110,7 +111,7 @@ struct ParsedQuery {
bool is_cacheable{true};
};
ParsedQuery ParseQuery(const std::string &query_string, const std::map<std::string, storage::PropertyValue> &params,
ParsedQuery ParseQuery(const std::string &query_string, const storage::PropertyValue::TMap &params,
utils::SkipList<QueryCacheEntry> *cache, utils::SpinLock *antlr_lock,
const InterpreterConfig::Query &query_config);

View File

@ -83,6 +83,7 @@ template <typename T>
void PrintObject(std::ostream *out, const T &arg);
void PrintObject(std::ostream *out, const std::string &str);
void PrintObject(std::ostream *out, const utils::pmr::string &str);
void PrintObject(std::ostream *out, Aggregation::Op op);
@ -95,9 +96,15 @@ void PrintObject(std::ostream *out, const storage::PropertyValue &value);
template <typename T>
void PrintObject(std::ostream *out, const std::vector<T> &vec);
template <typename T>
void PrintObject(std::ostream *out, const utils::pmr::vector<T> &vec);
template <typename K, typename V>
void PrintObject(std::ostream *out, const std::map<K, V> &map);
template <typename K, typename V>
void PrintObject(std::ostream *out, const utils::pmr::map<K, V> &map);
template <typename T>
void PrintObject(std::ostream *out, const T &arg) {
static_assert(!std::is_convertible<T, Expression *>::value,
@ -109,6 +116,7 @@ void PrintObject(std::ostream *out, const T &arg) {
}
void PrintObject(std::ostream *out, const std::string &str) { *out << utils::Escape(str); }
void PrintObject(std::ostream *out, const utils::pmr::string &str) { *out << utils::Escape(str); }
void PrintObject(std::ostream *out, Aggregation::Op op) { *out << Aggregation::OpToString(op); }
@ -165,6 +173,13 @@ void PrintObject(std::ostream *out, const std::vector<T> &vec) {
*out << "]";
}
template <typename T>
void PrintObject(std::ostream *out, const utils::pmr::vector<T> &vec) {
*out << "[";
utils::PrintIterable(*out, vec, ", ", [](auto &stream, const auto &item) { PrintObject(&stream, item); });
*out << "]";
}
template <typename K, typename V>
void PrintObject(std::ostream *out, const std::map<K, V> &map) {
*out << "{";
@ -176,6 +191,17 @@ void PrintObject(std::ostream *out, const std::map<K, V> &map) {
*out << "}";
}
template <typename K, typename V>
void PrintObject(std::ostream *out, const utils::pmr::map<K, V> &map) {
*out << "{";
utils::PrintIterable(*out, map, ", ", [](auto &stream, const auto &item) {
PrintObject(&stream, item.first);
stream << ": ";
PrintObject(&stream, item.second);
});
*out << "}";
}
template <typename T>
void PrintOperatorArgs(std::ostream *out, const T &arg) {
*out << " ";

View File

@ -1503,8 +1503,7 @@ TriggerEventType ToTriggerEventType(const TriggerQuery::EventType event_type) {
}
}
Callback CreateTrigger(TriggerQuery *trigger_query,
const std::map<std::string, storage::PropertyValue> &user_parameters,
Callback CreateTrigger(TriggerQuery *trigger_query, const storage::PropertyValue::TMap &user_parameters,
InterpreterContext *interpreter_context, DbAccessor *dba, std::optional<std::string> owner) {
return {
{},
@ -1554,7 +1553,7 @@ Callback ShowTriggers(InterpreterContext *interpreter_context) {
PreparedQuery PrepareTriggerQuery(ParsedQuery parsed_query, const bool in_explicit_transaction,
std::vector<Notification> *notifications, InterpreterContext *interpreter_context,
DbAccessor *dba, const std::map<std::string, storage::PropertyValue> &user_parameters,
DbAccessor *dba, const storage::PropertyValue::TMap &user_parameters,
const std::string *username) {
if (in_explicit_transaction) {
throw TriggerModificationInMulticommandTxException();
@ -1604,8 +1603,7 @@ PreparedQuery PrepareTriggerQuery(ParsedQuery parsed_query, const bool in_explic
PreparedQuery PrepareStreamQuery(ParsedQuery parsed_query, const bool in_explicit_transaction,
std::vector<Notification> *notifications, InterpreterContext *interpreter_context,
DbAccessor *dba,
const std::map<std::string, storage::PropertyValue> & /*user_parameters*/,
DbAccessor *dba, const storage::PropertyValue::TMap & /*user_parameters*/,
const std::string *username) {
if (in_explicit_transaction) {
throw StreamQueryInMulticommandTxException();
@ -2033,7 +2031,7 @@ void Interpreter::RollbackTransaction() {
}
Interpreter::PrepareResult Interpreter::Prepare(const std::string &query_string,
const std::map<std::string, storage::PropertyValue> &params,
const storage::PropertyValue::TMap &params,
const std::string *username) {
if (!in_explicit_transaction_) {
query_executions_.clear();

View File

@ -220,7 +220,7 @@ class Interpreter final {
*
* @throw query::QueryException
*/
PrepareResult Prepare(const std::string &query, const std::map<std::string, storage::PropertyValue> &params,
PrepareResult Prepare(const std::string &query, const storage::PropertyValue::TMap &params,
const std::string *username);
/**

View File

@ -1520,7 +1520,7 @@ storage::PropertyValue ToPropertyValue(const mgp_map &map) {
storage::PropertyValue result{std::map<std::string, storage::PropertyValue>{}};
auto &result_map = result.ValueMap();
for (const auto &[key, value] : map.items) {
result_map.insert_or_assign(std::string{key}, ToPropertyValue(value));
result_map.insert_or_assign(utils::pmr::string{key}, ToPropertyValue(value));
}
return result;
}

View File

@ -12,6 +12,7 @@
#include "query/serialization/property_value.hpp"
#include "storage/v2/property_value.hpp"
#include "utils/logging.hpp"
#include "utils/memory.hpp"
namespace query::serialization {
@ -46,7 +47,7 @@ nlohmann::json SerializePropertyValue(const storage::PropertyValue &property_val
}
}
nlohmann::json SerializePropertyValueVector(const std::vector<storage::PropertyValue> &values) {
nlohmann::json SerializePropertyValueVector(const storage::PropertyValue::TVector &values) {
nlohmann::json array = nlohmann::json::array();
for (const auto &value : values) {
array.push_back(SerializePropertyValue(value));
@ -54,6 +55,18 @@ nlohmann::json SerializePropertyValueVector(const std::vector<storage::PropertyV
return array;
}
nlohmann::json SerializePropertyValueMap(const storage::PropertyValue::TMap &parameters) {
nlohmann::json data = nlohmann::json::object();
data.emplace("type", static_cast<uint64_t>(ObjectType::MAP));
data.emplace("value", nlohmann::json::object());
for (const auto &[key, value] : parameters) {
data["value"][std::string{key}] = SerializePropertyValue(value);
}
return data;
};
nlohmann::json SerializePropertyValueMap(const std::map<std::string, storage::PropertyValue> &parameters) {
nlohmann::json data = nlohmann::json::object();
data.emplace("type", static_cast<uint64_t>(ObjectType::MAP));
@ -112,9 +125,9 @@ std::vector<storage::PropertyValue> DeserializePropertyValueList(const nlohmann:
return property_values;
}
std::map<std::string, storage::PropertyValue> DeserializePropertyValueMap(const nlohmann::json::object_t &data) {
storage::PropertyValue::TMap DeserializePropertyValueMap(const nlohmann::json::object_t &data) {
MG_ASSERT(data.at("type").get<ObjectType>() == ObjectType::MAP, "Invalid map serialization");
std::map<std::string, storage::PropertyValue> property_values;
storage::PropertyValue::TMap property_values{utils::NewDeleteResource()};
const nlohmann::json::object_t &values = data.at("value");
for (const auto &[key, value] : values) {

View File

@ -19,7 +19,9 @@ namespace query::serialization {
nlohmann::json SerializePropertyValue(const storage::PropertyValue &property_value);
nlohmann::json SerializePropertyValueVector(const std::vector<storage::PropertyValue> &values);
nlohmann::json SerializePropertyValueVector(const storage::PropertyValue::TVector &values);
nlohmann::json SerializePropertyValueMap(const storage::PropertyValue::TMap &parameters);
nlohmann::json SerializePropertyValueMap(const std::map<std::string, storage::PropertyValue> &parameters);
@ -27,6 +29,6 @@ storage::PropertyValue DeserializePropertyValue(const nlohmann::json &data);
std::vector<storage::PropertyValue> DeserializePropertyValueList(const nlohmann::json::array_t &data);
std::map<std::string, storage::PropertyValue> DeserializePropertyValueMap(const nlohmann::json::object_t &data);
storage::PropertyValue::TMap DeserializePropertyValueMap(const nlohmann::json::object_t &data);
} // namespace query::serialization

View File

@ -523,7 +523,7 @@ Streams::StreamsMap::iterator Streams::CreateConsumer(StreamsMap &map, const std
interpreter->Abort();
}};
const static std::map<std::string, storage::PropertyValue> empty_parameters{};
const static storage::PropertyValue::TMap empty_parameters{utils::NewDeleteResource()};
uint32_t i = 0;
while (true) {
try {

View File

@ -150,8 +150,7 @@ std::vector<std::pair<Identifier, TriggerIdentifierTag>> GetPredefinedIdentifier
}
} // namespace
Trigger::Trigger(std::string name, const std::string &query,
const std::map<std::string, storage::PropertyValue> &user_parameters,
Trigger::Trigger(std::string name, const std::string &query, const storage::PropertyValue::TMap &user_parameters,
const TriggerEventType event_type, utils::SkipList<QueryCacheEntry> *query_cache,
DbAccessor *db_accessor, utils::SpinLock *antlr_lock, const InterpreterConfig::Query &query_config,
std::optional<std::string> owner, const query::AuthChecker *auth_checker)
@ -333,11 +332,11 @@ void TriggerStore::RestoreTriggers(utils::SkipList<QueryCacheEntry> *query_cache
}
void TriggerStore::AddTrigger(std::string name, const std::string &query,
const std::map<std::string, storage::PropertyValue> &user_parameters,
TriggerEventType event_type, TriggerPhase phase,
utils::SkipList<QueryCacheEntry> *query_cache, DbAccessor *db_accessor,
utils::SpinLock *antlr_lock, const InterpreterConfig::Query &query_config,
std::optional<std::string> owner, const query::AuthChecker *auth_checker) {
const storage::PropertyValue::TMap &user_parameters, TriggerEventType event_type,
TriggerPhase phase, utils::SkipList<QueryCacheEntry> *query_cache,
DbAccessor *db_accessor, utils::SpinLock *antlr_lock,
const InterpreterConfig::Query &query_config, std::optional<std::string> owner,
const query::AuthChecker *auth_checker) {
std::unique_lock store_guard{store_lock_};
if (storage_.Get(name)) {
throw utils::BasicException("Trigger with the same name already exists.");

View File

@ -32,11 +32,10 @@
namespace query {
struct Trigger {
explicit Trigger(std::string name, const std::string &query,
const std::map<std::string, storage::PropertyValue> &user_parameters, TriggerEventType event_type,
utils::SkipList<QueryCacheEntry> *query_cache, DbAccessor *db_accessor, utils::SpinLock *antlr_lock,
const InterpreterConfig::Query &query_config, std::optional<std::string> owner,
const query::AuthChecker *auth_checker);
explicit Trigger(std::string name, const std::string &query, const storage::PropertyValue::TMap &user_parameters,
TriggerEventType event_type, utils::SkipList<QueryCacheEntry> *query_cache, DbAccessor *db_accessor,
utils::SpinLock *antlr_lock, const InterpreterConfig::Query &query_config,
std::optional<std::string> owner, const query::AuthChecker *auth_checker);
void Execute(DbAccessor *dba, utils::MonotonicBufferResource *execution_memory, double max_execution_time_sec,
std::atomic<bool> *is_shutting_down, const TriggerContext &context,
@ -84,10 +83,9 @@ struct TriggerStore {
utils::SpinLock *antlr_lock, const InterpreterConfig::Query &query_config,
const query::AuthChecker *auth_checker);
void AddTrigger(std::string name, const std::string &query,
const std::map<std::string, storage::PropertyValue> &user_parameters, TriggerEventType event_type,
TriggerPhase phase, utils::SkipList<QueryCacheEntry> *query_cache, DbAccessor *db_accessor,
utils::SpinLock *antlr_lock, const InterpreterConfig::Query &query_config,
void AddTrigger(std::string name, const std::string &query, const storage::PropertyValue::TMap &user_parameters,
TriggerEventType event_type, TriggerPhase phase, utils::SkipList<QueryCacheEntry> *query_cache,
DbAccessor *db_accessor, utils::SpinLock *antlr_lock, const InterpreterConfig::Query &query_config,
std::optional<std::string> owner, const query::AuthChecker *auth_checker);
void DropTrigger(const std::string &name);

View File

@ -19,6 +19,7 @@
#include <string_view>
#include <utility>
#include "storage/v2/property_value.hpp"
#include "storage/v2/temporal.hpp"
#include "utils/exceptions.hpp"
#include "utils/fnv.hpp"
@ -278,12 +279,18 @@ TypedValue::operator storage::PropertyValue() const {
case TypedValue::Type::Double:
return storage::PropertyValue(double_v);
case TypedValue::Type::String:
return storage::PropertyValue(std::string(string_v));
case TypedValue::Type::List:
return storage::PropertyValue(std::vector<storage::PropertyValue>(list_v.begin(), list_v.end()));
return storage::PropertyValue(string_v, memory_);
case TypedValue::Type::List: {
storage::PropertyValue::TVector list{memory_};
list.reserve(list_v.size());
for (const auto &tv : list_v) {
list.emplace_back(storage::PropertyValue(tv));
}
return storage::PropertyValue(std::move(list));
}
case TypedValue::Type::Map: {
std::map<std::string, storage::PropertyValue> map;
for (const auto &kv : map_v) map.emplace(kv.first, kv.second);
storage::PropertyValue::TMap map{memory_};
for (const auto &kv : map_v) map.emplace(kv.first, storage::PropertyValue(kv.second));
return storage::PropertyValue(std::move(map));
}
case Type::Date:

View File

@ -19,6 +19,10 @@
#include "storage/v2/temporal.hpp"
#include "utils/algorithm.hpp"
#include "utils/exceptions.hpp"
#include "utils/memory.hpp"
#include "utils/pmr/map.hpp"
#include "utils/pmr/string.hpp"
#include "utils/pmr/vector.hpp"
namespace storage {
@ -48,6 +52,12 @@ class PropertyValue {
TemporalData = 7
};
using TString = utils::pmr::string;
using TVector = utils::pmr::vector<PropertyValue>;
using TMap = utils::pmr::map<utils::pmr::string, PropertyValue>;
using allocator_type = utils::Allocator<PropertyValue>;
static bool AreComparableTypes(Type a, Type b) {
return (a == b) || (a == Type::Int && b == Type::Double) || (a == Type::Double && b == Type::Int);
}
@ -56,45 +66,204 @@ class PropertyValue {
PropertyValue() : type_(Type::Null) {}
// constructors for primitive types
explicit PropertyValue(const bool value) : type_(Type::Bool) { bool_v = value; }
explicit PropertyValue(const int value) : type_(Type::Int) { int_v = value; }
explicit PropertyValue(const int64_t value) : type_(Type::Int) { int_v = value; }
explicit PropertyValue(const double value) : type_(Type::Double) { double_v = value; }
explicit PropertyValue(const TemporalData value) : type_{Type::TemporalData} { temporal_data_v = value; }
explicit PropertyValue(const bool value, utils::MemoryResource *memory = utils::NewDeleteResource())
: type_(Type::Bool), memory_{memory} {
bool_v = value;
}
explicit PropertyValue(const int value, utils::MemoryResource *memory = utils::NewDeleteResource())
: type_(Type::Int), memory_{memory} {
int_v = value;
}
explicit PropertyValue(const int64_t value, utils::MemoryResource *memory = utils::NewDeleteResource())
: type_(Type::Int), memory_{memory} {
int_v = value;
}
explicit PropertyValue(const double value, utils::MemoryResource *memory = utils::NewDeleteResource())
: type_(Type::Double), memory_{memory} {
double_v = value;
}
explicit PropertyValue(const TemporalData value, utils::MemoryResource *memory = utils::NewDeleteResource())
: type_{Type::TemporalData}, memory_{memory} {
temporal_data_v = value;
}
// copy constructors for non-primitive types
/// @throw std::bad_alloc
explicit PropertyValue(const std::string &value) : type_(Type::String) { new (&string_v) std::string(value); }
explicit PropertyValue(const std::string &value, utils::MemoryResource *memory = utils::NewDeleteResource())
: type_(Type::String), memory_{memory} {
new (&string_v) TString(value, memory);
}
/// @throw std::bad_alloc
/// @throw std::length_error if length of value exceeds
/// std::string::max_length().
explicit PropertyValue(const char *value) : type_(Type::String) { new (&string_v) std::string(value); }
/// @throw std::bad_alloc
explicit PropertyValue(const std::vector<PropertyValue> &value) : type_(Type::List) {
new (&list_v) std::vector<PropertyValue>(value);
}
/// @throw std::bad_alloc
explicit PropertyValue(const std::map<std::string, PropertyValue> &value) : type_(Type::Map) {
new (&map_v) std::map<std::string, PropertyValue>(value);
explicit PropertyValue(const char *value, utils::MemoryResource *memory = utils::NewDeleteResource())
: type_(Type::String), memory_{memory} {
new (&string_v) TString(value, memory);
}
// move constructors for non-primitive types
explicit PropertyValue(std::string &&value) noexcept : type_(Type::String) {
new (&string_v) std::string(std::move(value));
/**
* Construct a copy of other.
* utils::MemoryResource is obtained by calling
* std::allocator_traits<>::
* select_on_container_copy_construction(other.get_allocator()).
* Since we use utils::Allocator, which does not propagate, this means that
* memory_ will be the default utils::NewDeleteResource().
*/
explicit PropertyValue(const TString &other)
: PropertyValue(other,
std::allocator_traits<utils::Allocator<PropertyValue>>::select_on_container_copy_construction(
other.get_allocator())
.GetMemoryResource()) {}
/** Construct a copy using the given utils::MemoryResource */
PropertyValue(const TString &other, utils::MemoryResource *memory) : type_(Type::String), memory_{memory} {
new (&string_v) TString(other, memory_);
}
explicit PropertyValue(std::vector<PropertyValue> &&value) noexcept : type_(Type::List) {
new (&list_v) std::vector<PropertyValue>(std::move(value));
/** Construct a copy using the given utils::MemoryResource */
explicit PropertyValue(const std::vector<PropertyValue> &value,
utils::MemoryResource *memory = utils::NewDeleteResource())
: type_(Type::List), memory_(memory) {
new (&list_v) TVector(memory_);
list_v.reserve(value.size());
list_v.assign(value.begin(), value.end());
}
explicit PropertyValue(std::map<std::string, PropertyValue> &&value) noexcept : type_(Type::Map) {
new (&map_v) std::map<std::string, PropertyValue>(std::move(value));
/**
* Construct a copy of other.
* utils::MemoryResource is obtained by calling
* std::allocator_traits<>::
* select_on_container_copy_construction(other.get_allocator()).
* Since we use utils::Allocator, which does not propagate, this means that
* memory_ will be the default utils::NewDeleteResource().
*/
explicit PropertyValue(const TVector &other)
: PropertyValue(other,
std::allocator_traits<utils::Allocator<PropertyValue>>::select_on_container_copy_construction(
other.get_allocator())
.GetMemoryResource()) {}
/** Construct a copy using the given utils::MemoryResource */
PropertyValue(const TVector &value, utils::MemoryResource *memory) : type_(Type::List), memory_(memory) {
new (&list_v) TVector(value, memory_);
}
/** Construct a copy using the given utils::MemoryResource */
explicit PropertyValue(const std::map<std::string, PropertyValue> &value,
utils::MemoryResource *memory = utils::NewDeleteResource())
: type_(Type::Map), memory_{memory} {
new (&map_v) TMap(memory_);
for (const auto &kv : value) map_v.emplace(kv.first, kv.second);
}
/**
* Construct a copy of other.
* utils::MemoryResource is obtained by calling
* std::allocator_traits<>::
* select_on_container_copy_construction(other.get_allocator()).
* Since we use utils::Allocator, which does not propagate, this means that
* memory_ will be the default utils::NewDeleteResource().
*/
explicit PropertyValue(const TMap &other)
: PropertyValue(other,
std::allocator_traits<utils::Allocator<PropertyValue>>::select_on_container_copy_construction(
other.get_allocator())
.GetMemoryResource()) {}
/** Construct a copy using the given utils::MemoryResource */
PropertyValue(const TMap &value, utils::MemoryResource *memory) : type_(Type::Map), memory_{memory} {
new (&map_v) TMap(value, memory_);
}
/**
* Construct with the value of other.
* utils::MemoryResource is obtained from other. After the move, other will be
* left in unspecified state.
*/
explicit PropertyValue(TString &&other) noexcept
: PropertyValue(std::move(other), other.get_allocator().GetMemoryResource()) {}
/**
* Construct with the value of other and use the given MemoryResource
* After the move, other will be left in unspecified state.
*/
PropertyValue(TString &&other, utils::MemoryResource *memory) : type_(Type::String), memory_{memory} {
new (&string_v) TString(std::move(other), memory_);
}
/**
* Perform an element-wise move using default utils::NewDeleteResource().
* Other will be not be empty, though elements may be Null.
*/
explicit PropertyValue(std::vector<PropertyValue> &&other)
: PropertyValue(std::move(other), utils::NewDeleteResource()) {}
/**
* Perform an element-wise move of the other and use the given MemoryResource.
* Other will be not be left empty, though elements may be Null.
*/
PropertyValue(std::vector<PropertyValue> &&other, utils::MemoryResource *memory)
: type_(Type::List), memory_{memory} {
new (&list_v) TVector(memory_);
list_v.reserve(other.size());
// std::vector<PropertyValue> has std::allocator and there's no move
// constructor for std::vector using different allocator types. Since
// std::allocator is not propagated to elements, it is possible that some
// PropertyValue elements have a MemoryResource that is the same as the one we
// are given. In such a case we would like to move those PropertyValue
// instances, so we use move_iterator.
list_v.assign(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
}
/**
* Construct with the value of other.
* utils::MemoryResource is obtained from other. After the move, other will be
* left empty.
*/
explicit PropertyValue(TVector &&other) noexcept
: PropertyValue(std::move(other), other.get_allocator().GetMemoryResource()) {}
/**
* Construct with the value of other and use the given MemoryResource.
* If `other.get_allocator() != *memory`, this call will perform an
* element-wise move and other is not guaranteed to be empty.
*/
PropertyValue(TVector &&other, utils::MemoryResource *memory) : type_(Type::List), memory_{memory} {
new (&list_v) TVector(std::move(other), memory_);
}
/**
* Perform an element-wise move using default utils::NewDeleteResource().
* Other will not be left empty, i.e. keys will exist but their values may
* be Null.
*/
explicit PropertyValue(std::map<std::string, PropertyValue> &&other)
: PropertyValue(std::move(other), utils::NewDeleteResource()) {}
/**
* Perform an element-wise move using the given MemoryResource.
* Other will not be left empty, i.e. keys will exist but their values may
* be Null.
*/
PropertyValue(std::map<std::string, PropertyValue> &&other, utils::MemoryResource *memory)
: type_(Type::Map), memory_{memory} {
new (&map_v) TMap(memory_);
for (auto &kv : other) map_v.emplace(kv.first, std::move(kv.second));
}
/**
* Construct with the value of other.
* utils::MemoryResource is obtained from other. After the move, other will be
* left empty.
*/
explicit PropertyValue(TMap &&other) noexcept
: PropertyValue(std::move(other), other.get_allocator().GetMemoryResource()) {}
// copy constructor
/// @throw std::bad_alloc
PropertyValue(const PropertyValue &other);
PropertyValue(const PropertyValue &other, utils::MemoryResource *memory);
// move constructor
PropertyValue(PropertyValue &&other) noexcept;
PropertyValue(PropertyValue &&other, utils::MemoryResource *memory) noexcept;
// copy assignment
/// @throw std::bad_alloc
@ -153,7 +322,7 @@ class PropertyValue {
// const value getters for non-primitive types
/// @throw PropertyValueException if value isn't of correct type.
const std::string &ValueString() const {
const TString &ValueString() const {
if (type_ != Type::String) {
throw PropertyValueException("The value isn't a string!");
}
@ -161,7 +330,7 @@ class PropertyValue {
}
/// @throw PropertyValueException if value isn't of correct type.
const std::vector<PropertyValue> &ValueList() const {
const TVector &ValueList() const {
if (type_ != Type::List) {
throw PropertyValueException("The value isn't a list!");
}
@ -169,7 +338,7 @@ class PropertyValue {
}
/// @throw PropertyValueException if value isn't of correct type.
const std::map<std::string, PropertyValue> &ValueMap() const {
const TMap &ValueMap() const {
if (type_ != Type::Map) {
throw PropertyValueException("The value isn't a map!");
}
@ -178,7 +347,7 @@ class PropertyValue {
// reference value getters for non-primitive types
/// @throw PropertyValueException if value isn't of correct type.
std::string &ValueString() {
TString &ValueString() {
if (type_ != Type::String) {
throw PropertyValueException("The value isn't a string!");
}
@ -186,7 +355,7 @@ class PropertyValue {
}
/// @throw PropertyValueException if value isn't of correct type.
std::vector<PropertyValue> &ValueList() {
TVector &ValueList() {
if (type_ != Type::List) {
throw PropertyValueException("The value isn't a list!");
}
@ -194,7 +363,7 @@ class PropertyValue {
}
/// @throw PropertyValueException if value isn't of correct type.
std::map<std::string, PropertyValue> &ValueMap() {
TMap &ValueMap() {
if (type_ != Type::Map) {
throw PropertyValueException("The value isn't a map!");
}
@ -208,13 +377,14 @@ class PropertyValue {
bool bool_v;
int64_t int_v;
double double_v;
std::string string_v;
std::vector<PropertyValue> list_v;
std::map<std::string, PropertyValue> map_v;
TString string_v;
TVector list_v;
TMap map_v;
TemporalData temporal_data_v;
};
Type type_;
utils::MemoryResource *memory_{utils::NewDeleteResource()};
};
// stream output
@ -329,8 +499,14 @@ inline bool operator<(const PropertyValue &first, const PropertyValue &second) n
return first.ValueTemporalData() < second.ValueTemporalData();
}
}
inline PropertyValue::PropertyValue(const PropertyValue &other)
: PropertyValue(
other,
std::allocator_traits<utils::Allocator<PropertyValue>>::select_on_container_copy_construction(other.memory_)
.GetMemoryResource()) {}
inline PropertyValue::PropertyValue(const PropertyValue &other) : type_(other.type_) {
inline PropertyValue::PropertyValue(const PropertyValue &other, utils::MemoryResource *memory)
: type_(other.type_), memory_{memory} {
switch (other.type_) {
case Type::Null:
return;
@ -344,13 +520,13 @@ inline PropertyValue::PropertyValue(const PropertyValue &other) : type_(other.ty
this->double_v = other.double_v;
return;
case Type::String:
new (&string_v) std::string(other.string_v);
new (&string_v) TString(other.string_v, memory_);
return;
case Type::List:
new (&list_v) std::vector<PropertyValue>(other.list_v);
new (&list_v) TVector(other.list_v, memory_);
return;
case Type::Map:
new (&map_v) std::map<std::string, PropertyValue>(other.map_v);
new (&map_v) TMap(other.map_v, memory_);
return;
case Type::TemporalData:
this->temporal_data_v = other.temporal_data_v;
@ -358,7 +534,10 @@ inline PropertyValue::PropertyValue(const PropertyValue &other) : type_(other.ty
}
}
inline PropertyValue::PropertyValue(PropertyValue &&other) noexcept : type_(other.type_) {
inline PropertyValue::PropertyValue(PropertyValue &&other) noexcept : PropertyValue(std::move(other), other.memory_) {}
inline PropertyValue::PropertyValue(PropertyValue &&other, utils::MemoryResource *memory) noexcept
: type_(other.type_), memory_{memory} {
switch (other.type_) {
case Type::Null:
break;
@ -372,13 +551,13 @@ inline PropertyValue::PropertyValue(PropertyValue &&other) noexcept : type_(othe
this->double_v = other.double_v;
break;
case Type::String:
new (&string_v) std::string(std::move(other.string_v));
new (&string_v) TString(std::move(other.string_v), memory_);
break;
case Type::List:
new (&list_v) std::vector<PropertyValue>(std::move(other.list_v));
new (&list_v) TVector(std::move(other.list_v), memory_);
break;
case Type::Map:
new (&map_v) std::map<std::string, PropertyValue>(std::move(other.map_v));
new (&map_v) TMap(std::move(other.map_v), memory_);
break;
case Type::TemporalData:
this->temporal_data_v = other.temporal_data_v;
@ -409,13 +588,13 @@ inline PropertyValue &PropertyValue::operator=(const PropertyValue &other) {
this->double_v = other.double_v;
break;
case Type::String:
new (&string_v) std::string(other.string_v);
new (&string_v) TString(other.string_v, memory_);
break;
case Type::List:
new (&list_v) std::vector<PropertyValue>(other.list_v);
new (&list_v) TVector(other.list_v, memory_);
break;
case Type::Map:
new (&map_v) std::map<std::string, PropertyValue>(other.map_v);
new (&map_v) TMap(other.map_v, memory_);
break;
case Type::TemporalData:
this->temporal_data_v = other.temporal_data_v;
@ -444,13 +623,13 @@ inline PropertyValue &PropertyValue::operator=(PropertyValue &&other) noexcept {
this->double_v = other.double_v;
break;
case Type::String:
new (&string_v) std::string(std::move(other.string_v));
new (&string_v) TString(std::move(other.string_v), memory_);
break;
case Type::List:
new (&list_v) std::vector<PropertyValue>(std::move(other.list_v));
new (&list_v) TVector(std::move(other.list_v), memory_);
break;
case Type::Map:
new (&map_v) std::map<std::string, PropertyValue>(std::move(other.map_v));
new (&map_v) TMap(std::move(other.map_v), memory_);
break;
case Type::TemporalData:
this->temporal_data_v = other.temporal_data_v;