Continuing major refactor, UNSTABLE STATE. Merged current dev
This commit is contained in:
commit
ee523d5080
@ -145,7 +145,11 @@ class SkipList : private Lockable<lock_t> {
|
||||
}
|
||||
|
||||
static Node *create(const T &item, uint8_t height) {
|
||||
return create(height, item);
|
||||
auto node = allocate(height);
|
||||
|
||||
// we have raw memory and we need to construct an object
|
||||
// of type Node on it
|
||||
return new (node) Node(item, height);
|
||||
}
|
||||
|
||||
static Node *create(T &&item, uint8_t height) {
|
||||
@ -188,6 +192,10 @@ class SkipList : private Lockable<lock_t> {
|
||||
this->data.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
Node(const T &data, uint8_t height) : Node(height) {
|
||||
this->data.set(data);
|
||||
}
|
||||
|
||||
Node(T &&data, uint8_t height) : Node(height) {
|
||||
this->data.set(std::move(data));
|
||||
}
|
||||
@ -940,6 +948,42 @@ class SkipList : private Lockable<lock_t> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert unique data
|
||||
*
|
||||
* F - type of funct which will create new node if needed. Recieves height
|
||||
* of node.
|
||||
*/
|
||||
// TODO this code is not DRY w.r.t. the other insert function (rvalue ref)
|
||||
std::pair<Iterator, bool> insert(Node *preds[], Node *succs[], const T &data) {
|
||||
while (true) {
|
||||
// TODO: before here was data.first
|
||||
auto level = find_path(this, H - 1, data, preds, succs);
|
||||
|
||||
if (level != -1) {
|
||||
auto found = succs[level];
|
||||
|
||||
if (found->flags.is_marked()) continue;
|
||||
|
||||
while (!found->flags.is_fully_linked()) usleep(250);
|
||||
|
||||
return {Iterator{succs[level]}, false};
|
||||
}
|
||||
|
||||
auto height = rnd();
|
||||
guard_t guards[H];
|
||||
|
||||
// try to acquire the locks for predecessors up to the height of
|
||||
// the new node. release the locks and try again if someone else
|
||||
// has the locks
|
||||
if (!lock_nodes<true>(height, guards, preds, succs)) continue;
|
||||
|
||||
return {insert_here(Node::create(data, height), preds, succs,
|
||||
height, guards),
|
||||
true};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert unique data
|
||||
*
|
||||
|
117
include/storage/model/typed_value.hpp
Normal file
117
include/storage/model/typed_value.hpp
Normal file
@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/underlying_cast.hpp"
|
||||
#include "utils/total_ordering.hpp"
|
||||
#include "utils/exceptions/basic_exception.hpp"
|
||||
|
||||
/**
|
||||
* Encapsulation of a value and it's type encapsulated in a class that has no
|
||||
* compiled-time info about that type.
|
||||
*
|
||||
* Values can be of a number of predefined types that are enumerated in
|
||||
* TypedValue::Type. Each such type corresponds to exactly one C++ type.
|
||||
*/
|
||||
class TypedValue : public TotalOrdering<TypedValue, TypedValue, TypedValue> {
|
||||
|
||||
private:
|
||||
/** Private default constructor, makes Null */
|
||||
TypedValue() : type_(Type::Null) {}
|
||||
|
||||
public:
|
||||
|
||||
/** A value type. Each type corresponds to exactly one C++ type */
|
||||
enum class Type : unsigned {
|
||||
Null,
|
||||
String,
|
||||
Bool,
|
||||
Int,
|
||||
Float
|
||||
};
|
||||
|
||||
// single static reference to Null, used whenever Null should be returned
|
||||
static const TypedValue Null;
|
||||
|
||||
// constructors for primitive types
|
||||
TypedValue(bool value) : type_(Type::Bool) { bool_v = value; }
|
||||
TypedValue(int value) : type_(Type::Int) { int_v = value; }
|
||||
TypedValue(float value) : type_(Type::Float) { float_v = value; }
|
||||
|
||||
/// constructors for non-primitive types (shared pointers)
|
||||
TypedValue(const std::string &value) : type_(Type::String) {
|
||||
new (&string_v) std::shared_ptr<std::string>(new std::string(value));
|
||||
}
|
||||
TypedValue(const char* value) : type_(Type::String) {
|
||||
new (&string_v) std::shared_ptr<std::string>(new std::string(value));
|
||||
}
|
||||
|
||||
// assignment ops
|
||||
TypedValue& operator=(TypedValue& other);
|
||||
TypedValue& operator=(TypedValue&& other);
|
||||
|
||||
TypedValue(const TypedValue& other);
|
||||
~TypedValue();
|
||||
|
||||
/**
|
||||
* Returns the value of the property as given type T.
|
||||
* The behavior of this function is undefined if
|
||||
* T does not correspond to this property's type_.
|
||||
*
|
||||
* @tparam T Type to interpret the value as.
|
||||
* @return The value as type T.
|
||||
*/
|
||||
template <typename T> T Value() const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const TypedValue& prop);
|
||||
|
||||
/**
|
||||
* The Type of property.
|
||||
*/
|
||||
const Type type_;
|
||||
|
||||
private:
|
||||
// storage for the value of the property
|
||||
union {
|
||||
bool bool_v;
|
||||
int int_v;
|
||||
float float_v;
|
||||
std::shared_ptr<std::string> string_v;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* An exception raised by the TypedValue system. Typically when
|
||||
* trying to perform operations (such as addition) on TypedValues
|
||||
* of incompatible Types.
|
||||
*/
|
||||
class TypedValueException : public BasicException {
|
||||
|
||||
public:
|
||||
using ::BasicException::BasicException;
|
||||
};
|
||||
|
||||
// comparison operators
|
||||
// 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);
|
||||
|
||||
// arithmetic operators
|
||||
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);
|
||||
|
||||
// binary bool operators
|
||||
TypedValue operator&&(const TypedValue& a, const TypedValue& b);
|
||||
TypedValue operator||(const TypedValue& a, const TypedValue& b);
|
||||
|
||||
// stream output
|
||||
std::ostream &operator<<(std::ostream &os, const TypedValue::Type type);
|
82
include/storage/model/typed_value_store.hpp
Normal file
82
include/storage/model/typed_value_store.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "typed_value.hpp"
|
||||
|
||||
/**
|
||||
* A collection of properties accessed in a map-like way
|
||||
* using a key of type Properties::TKey.
|
||||
*
|
||||
* The underlying implementation is not necessarily std::map.
|
||||
*/
|
||||
class TypedValueStore {
|
||||
public:
|
||||
using sptr = std::shared_ptr<TypedValueStore>;
|
||||
|
||||
/** The type of key used to get and set properties */
|
||||
using TKey = uint32_t;
|
||||
|
||||
/**
|
||||
* Returns a TypedValue (by reference) at the given key.
|
||||
* If the key does not exist, the Null property is returned.
|
||||
*
|
||||
* This is NOT thread-safe, the reference might not be valid
|
||||
* when used in a multithreaded scenario.
|
||||
*
|
||||
* @param key The key for which a TypedValue is sought.
|
||||
* @return See above.
|
||||
*/
|
||||
const TypedValue &at(const TKey &key) const;
|
||||
|
||||
/**
|
||||
* Sets the value for the given key. A new TypedValue instance
|
||||
* is created for the given value (which is of raw type).
|
||||
*
|
||||
* @tparam TValue Type of value. It must be one of the
|
||||
* predefined possible TypedValue values (bool, string, int...)
|
||||
* @param key The key for which the property is set. The previous
|
||||
* value at the same key (if there was one) is replaced.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
template<typename TValue>
|
||||
void set(const TKey &key, const TValue &value);
|
||||
|
||||
/**
|
||||
* Set overriding for character constants. Forces conversion
|
||||
* to std::string, otherwise templating might cast the pointer
|
||||
* to something else (bool) and mess things up.
|
||||
*
|
||||
* @param key The key for which the property is set. The previous
|
||||
* value at the same key (if there was one) is replaced.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
void set(const TKey &key, const char *value);
|
||||
|
||||
/**
|
||||
* Removes the TypedValue for the given key.
|
||||
*
|
||||
* @param key The key for which to remove the property.
|
||||
* @return The number of removed properties (0 or 1).
|
||||
*/
|
||||
size_t erase(const TKey &key);
|
||||
|
||||
/**
|
||||
* @return The number of Properties in this collection.
|
||||
*/
|
||||
size_t size() const;
|
||||
|
||||
|
||||
/**
|
||||
* Accepts two functions.
|
||||
*
|
||||
* @param handler Called for each TypedValue in this collection.
|
||||
* @param finish Called once in the end.
|
||||
*/
|
||||
void Accept(std::function<void(const TKey key, const TypedValue& prop)> handler,
|
||||
std::function<void()> finish = {}) const;
|
||||
|
||||
private:
|
||||
std::vector<std::pair<TKey, TypedValue>> props_;
|
||||
};
|
57
include/storage/model/typed_value_utils.h
Normal file
57
include/storage/model/typed_value_utils.h
Normal file
@ -0,0 +1,57 @@
|
||||
//
|
||||
// Copyright 2017 Memgraph
|
||||
// Created by Florijan Stamenkovic on 01.02.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
#include "storage/model/typed_value_store.hpp"
|
||||
|
||||
|
||||
/**
|
||||
* Writes all of the values from the given store in JSON format
|
||||
* to the given output stream.
|
||||
*
|
||||
* @param store The store that should be serialized to JSON.
|
||||
* @param ostream The stream to write to.
|
||||
*/
|
||||
void TypedValuesToJson(const TypedValueStore& store,
|
||||
std::ostream& ostream=std::cout) {
|
||||
|
||||
bool first = true;
|
||||
|
||||
auto write_key = [&ostream, &first](const TypedValueStore::TKey &key) -> std::ostream& {
|
||||
if (first) {
|
||||
ostream << '{';
|
||||
first = false;
|
||||
} else
|
||||
ostream << ',';
|
||||
|
||||
return ostream << '"' << key << "\":";
|
||||
};
|
||||
|
||||
auto handler = [&ostream, &write_key](const TypedValueStore::TKey& key,
|
||||
const TypedValue& value) {
|
||||
switch (value.type_) {
|
||||
case TypedValue::Type::Null:
|
||||
break;
|
||||
case TypedValue::Type::Bool:
|
||||
write_key(key) << (value.Value<bool>() ? "true" : "false");
|
||||
break;
|
||||
case TypedValue::Type::String:
|
||||
write_key(key) << '"' << value.Value<std::string>() << '"';
|
||||
break;
|
||||
case TypedValue::Type::Int:
|
||||
write_key(key) << value.Value<int>();
|
||||
break;
|
||||
case TypedValue::Type::Float:
|
||||
write_key(key) << value.Value<float>();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
auto finish = [&ostream]() { ostream << '}' << std::endl; };
|
||||
|
||||
store.Accept(handler, finish);
|
||||
}
|
363
src/storage/model/typed_value.cpp
Normal file
363
src/storage/model/typed_value.cpp
Normal file
@ -0,0 +1,363 @@
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "storage/model/typed_value.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
|
||||
// Value extraction template instantiations
|
||||
template<>
|
||||
bool TypedValue::Value<bool>() const {
|
||||
runtime_assert(type_ == TypedValue::Type::Bool, "Incompatible template param and type");
|
||||
return bool_v;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string TypedValue::Value<std::string>() const {
|
||||
runtime_assert(type_ == TypedValue::Type::String, "Incompatible template param and type");
|
||||
return *string_v;
|
||||
}
|
||||
|
||||
template<>
|
||||
int TypedValue::Value<int>() const {
|
||||
runtime_assert(type_ == TypedValue::Type::Int, "Incompatible template param and type");
|
||||
return int_v;
|
||||
}
|
||||
|
||||
template<>
|
||||
float TypedValue::Value<float>() const {
|
||||
runtime_assert(type_ == TypedValue::Type::Float, "Incompatible template param and type");
|
||||
return float_v;
|
||||
}
|
||||
|
||||
TypedValue::TypedValue(const TypedValue &other) : type_(other.type_) {
|
||||
switch (other.type_) {
|
||||
case TypedValue::Type::Null:
|
||||
return;
|
||||
|
||||
case TypedValue::Type::Bool:
|
||||
this->bool_v = other.bool_v;
|
||||
return;
|
||||
|
||||
case TypedValue::Type::String:
|
||||
new(&string_v) std::shared_ptr<std::string>(other.string_v);
|
||||
return;
|
||||
|
||||
case Type::Int:
|
||||
this->int_v = other.int_v;
|
||||
return;
|
||||
|
||||
case Type::Float:
|
||||
this->float_v = other.float_v;
|
||||
return;
|
||||
}
|
||||
|
||||
permanent_fail("Unsupported TypedValue::Type");
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const TypedValue::Type type) {
|
||||
switch (type) {
|
||||
case TypedValue::Type::Null:
|
||||
return os << "null";
|
||||
case TypedValue::Type::Bool:
|
||||
return os << "bool";
|
||||
case TypedValue::Type::String:
|
||||
return os << "string";
|
||||
case TypedValue::Type::Int:
|
||||
return os << "int";
|
||||
case TypedValue::Type::Float:
|
||||
return os << "float";
|
||||
}
|
||||
permanent_fail("Unsupported TypedValue::Type");
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const TypedValue &property) {
|
||||
switch (property.type_) {
|
||||
case TypedValue::Type::Null:
|
||||
return os << "Null";
|
||||
case TypedValue::Type::Bool:
|
||||
return os << (property.Value<bool>() ? "true" : "false");
|
||||
case TypedValue::Type::String:
|
||||
return os << property.Value<std::string>();
|
||||
case TypedValue::Type::Int:
|
||||
return os << property.Value<int>();
|
||||
case TypedValue::Type::Float:
|
||||
return os << property.Value<float>();
|
||||
}
|
||||
permanent_fail("Unsupported TypedValue::Type");
|
||||
}
|
||||
|
||||
TypedValue &TypedValue::operator=(TypedValue &&other) {
|
||||
|
||||
// set the type of this
|
||||
const_cast<Type&>(type_) = other.type_;
|
||||
|
||||
if (this != &other) {
|
||||
switch (other.type_) {
|
||||
case TypedValue::Type::Null:
|
||||
case TypedValue::Type::Bool:
|
||||
this->bool_v = other.bool_v;
|
||||
return *this;
|
||||
case TypedValue::Type::String:
|
||||
this->string_v = std::move(other.string_v);
|
||||
return *this;
|
||||
case TypedValue::Type::Int:
|
||||
this->int_v = other.int_v;
|
||||
return *this;
|
||||
case TypedValue::Type::Float:
|
||||
this->float_v = other.float_v;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
permanent_fail("Unsupported TypedValue::Type");
|
||||
}
|
||||
|
||||
const TypedValue TypedValue::Null = TypedValue();
|
||||
|
||||
TypedValue::~TypedValue() {
|
||||
|
||||
switch (type_) {
|
||||
// destructor for primitive types does nothing
|
||||
case Type::Null:
|
||||
case Type::Bool:
|
||||
case Type::Int:
|
||||
case Type::Float:
|
||||
return;
|
||||
|
||||
// destructor for shared pointer must release
|
||||
case Type::String:
|
||||
string_v.~shared_ptr<std::string>();
|
||||
return;
|
||||
}
|
||||
permanent_fail("Unsupported TypedValue::Type");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the float value of a property.
|
||||
* The property MUST be either Float or Int.
|
||||
*
|
||||
* @param prop
|
||||
* @return
|
||||
*/
|
||||
float ToFloat(const TypedValue& prop) {
|
||||
switch (prop.type_) {
|
||||
case TypedValue::Type::Int:
|
||||
return (float)prop.Value<int>();
|
||||
case TypedValue::Type::Float:
|
||||
return prop.Value<float>();
|
||||
|
||||
default:
|
||||
permanent_fail("Unsupported TypedValue::Type");
|
||||
}
|
||||
}
|
||||
|
||||
TypedValue operator<(const TypedValue& a, const TypedValue& b) {
|
||||
if (a.type_ == TypedValue::Type::Bool || b.type_ == TypedValue::Type::Bool)
|
||||
throw TypedValueException("Invalid 'less' operand types({} + {})", a.type_, b.type_);
|
||||
|
||||
if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
|
||||
return TypedValue::Null;
|
||||
|
||||
if (a.type_ == TypedValue::Type::String || b.type_ == TypedValue::Type::String) {
|
||||
if (a.type_ != b.type_)
|
||||
throw TypedValueException("Invalid equality operand types({} + {})", a.type_, b.type_);
|
||||
else
|
||||
return a.Value<std::string>() < b.Value<std::string>();
|
||||
}
|
||||
|
||||
// at this point we only have int and float
|
||||
if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float)
|
||||
return ToFloat(a) < ToFloat(b);
|
||||
else
|
||||
return a.Value<int>() < b.Value<int>();
|
||||
}
|
||||
|
||||
TypedValue operator==(const TypedValue& a, const TypedValue& b) {
|
||||
|
||||
if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
|
||||
return TypedValue::Null;
|
||||
|
||||
if (a.type_ == TypedValue::Type::String || b.type_ == TypedValue::Type::String) {
|
||||
if (a.type_ != b.type_)
|
||||
throw TypedValueException("Invalid equality operand types({} + {})", a.type_, b.type_);
|
||||
else
|
||||
return a.Value<std::string>() == b.Value<std::string>();
|
||||
}
|
||||
|
||||
if (a.type_ == TypedValue::Type::Bool || b.type_ == TypedValue::Type::Bool) {
|
||||
if (a.type_ != b.type_)
|
||||
throw TypedValueException("Invalid equality operand types({} + {})", a.type_, b.type_);
|
||||
else
|
||||
return a.Value<bool>() == b.Value<bool>();
|
||||
}
|
||||
// at this point we only have int and float
|
||||
if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float){
|
||||
return ToFloat(a) == ToFloat(b);
|
||||
} else
|
||||
return a.Value<int>() == b.Value<int>();
|
||||
|
||||
}
|
||||
|
||||
TypedValue operator!(const TypedValue& a) {
|
||||
switch (a.type_) {
|
||||
case TypedValue::Type::Null:
|
||||
return TypedValue::Null;
|
||||
case TypedValue::Type::Bool:
|
||||
return TypedValue(!a.Value<bool>());
|
||||
|
||||
default:
|
||||
throw TypedValueException("Invalid logical not operand type (!{})", a.type_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a numeric or string property into a string.
|
||||
*
|
||||
* @param prop Property.
|
||||
* @return A string.
|
||||
*/
|
||||
std::string PropToString(const TypedValue& prop) {
|
||||
switch (prop.type_) {
|
||||
case TypedValue::Type::String:
|
||||
return prop.Value<std::string>();
|
||||
case TypedValue::Type::Int:
|
||||
return std::to_string(prop.Value<int>());
|
||||
case TypedValue::Type::Float:
|
||||
return fmt::format("{}", prop.Value<float>());
|
||||
|
||||
// unsupported situations
|
||||
default:
|
||||
permanent_fail("Unsupported TypedValue::Type");
|
||||
}
|
||||
}
|
||||
|
||||
TypedValue operator-(const TypedValue &a) {
|
||||
switch (a.type_) {
|
||||
case TypedValue::Type::Null:
|
||||
return TypedValue::Null;
|
||||
case TypedValue::Type::Int:
|
||||
return -a.Value<int>();
|
||||
case TypedValue::Type::Float:
|
||||
return -a.Value<float>();
|
||||
|
||||
default:
|
||||
throw TypedValueException("Invalid unary minus operand type (-{})", a.type_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Raises a PropertyException if the given properties do not support arithmetic
|
||||
* operations. If they do, nothing happens.
|
||||
*
|
||||
* @param a First prop.
|
||||
* @param b Second prop.
|
||||
* @param string_ok If or not for the given operation it's valid to work with
|
||||
* String values (typically it's OK only for sum).
|
||||
* @param op_name Name of the operation, used only for exception description,
|
||||
* if raised.
|
||||
*/
|
||||
inline void EnsureArithmeticallyOk(const TypedValue& a, const TypedValue& b,
|
||||
bool string_ok, const std::string& op_name) {
|
||||
if (a.type_ == TypedValue::Type::Bool || b.type_ == TypedValue::Type::Bool)
|
||||
throw TypedValueException("Invalid {} operand types {}, {}", op_name, a.type_, b.type_);
|
||||
|
||||
if (string_ok)
|
||||
return;
|
||||
|
||||
if (a.type_ == TypedValue::Type::String || b.type_ == TypedValue::Type::String)
|
||||
throw TypedValueException("Invalid subtraction operands types {}, {}", a.type_, b.type_);
|
||||
}
|
||||
|
||||
TypedValue operator+(const TypedValue& a, const TypedValue& b){
|
||||
EnsureArithmeticallyOk(a, b, true, "addition");
|
||||
if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
|
||||
return TypedValue::Null;
|
||||
|
||||
// no more Bool nor Null, summing works on anything from here onward
|
||||
|
||||
if (a.type_ == TypedValue::Type::String || b.type_ == TypedValue::Type::String)
|
||||
return PropToString(a) + PropToString(b);
|
||||
|
||||
// at this point we only have int and float
|
||||
if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float){
|
||||
return ToFloat(a) + ToFloat(b);
|
||||
} else
|
||||
return a.Value<int>() + b.Value<int>();
|
||||
}
|
||||
|
||||
TypedValue operator-(const TypedValue& a, const TypedValue& b){
|
||||
EnsureArithmeticallyOk(a, b, false, "subtraction");
|
||||
|
||||
if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
|
||||
return TypedValue::Null;
|
||||
|
||||
// at this point we only have int and float
|
||||
if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float){
|
||||
return ToFloat(a) - ToFloat(b);
|
||||
} else
|
||||
return a.Value<int>() - b.Value<int>();
|
||||
}
|
||||
|
||||
TypedValue operator/(const TypedValue& a, const TypedValue& b){
|
||||
EnsureArithmeticallyOk(a, b, false, "division");
|
||||
|
||||
if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
|
||||
return TypedValue::Null;
|
||||
|
||||
// at this point we only have int and float
|
||||
if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float){
|
||||
return ToFloat(a) / ToFloat(b);
|
||||
} else
|
||||
return a.Value<int>() / b.Value<int>();
|
||||
}
|
||||
|
||||
TypedValue operator*(const TypedValue& a, const TypedValue& b){
|
||||
EnsureArithmeticallyOk(a, b, false, "multiplication");
|
||||
|
||||
if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
|
||||
return TypedValue::Null;
|
||||
|
||||
// at this point we only have int and float
|
||||
if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float){
|
||||
return ToFloat(a) * ToFloat(b);
|
||||
} else
|
||||
return a.Value<int>() * b.Value<int>();
|
||||
}
|
||||
|
||||
TypedValue operator%(const TypedValue& a, const TypedValue& b){
|
||||
EnsureArithmeticallyOk(a, b, false, "modulo");
|
||||
|
||||
if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
|
||||
return TypedValue::Null;
|
||||
|
||||
// at this point we only have int and float
|
||||
if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float){
|
||||
return (float)fmod(ToFloat(a), ToFloat(b));
|
||||
} else
|
||||
return a.Value<int>() % b.Value<int>();
|
||||
}
|
||||
|
||||
inline bool IsLogicallyOk(const TypedValue& a) {
|
||||
return a.type_ == TypedValue::Type::Bool || a.type_ == TypedValue::Type::Null;
|
||||
}
|
||||
|
||||
TypedValue operator&&(const TypedValue& a, const TypedValue& b) {
|
||||
if(IsLogicallyOk(a) && IsLogicallyOk(b)){
|
||||
if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
|
||||
return TypedValue::Null;
|
||||
else
|
||||
return a.Value<bool>() && b.Value<bool>();
|
||||
} else
|
||||
throw TypedValueException("Invalid logical and operand types({} && {})", a.type_, b.type_);
|
||||
}
|
||||
|
||||
TypedValue operator||(const TypedValue& a, const TypedValue& b) {
|
||||
if(IsLogicallyOk(a) && IsLogicallyOk(b)){
|
||||
if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
|
||||
return TypedValue::Null;
|
||||
else
|
||||
return a.Value<bool>() || b.Value<bool>();
|
||||
} else
|
||||
throw TypedValueException("Invalid logical and operand types({} && {})", a.type_, b.type_);
|
||||
}
|
68
src/storage/model/typed_value_store.cpp
Normal file
68
src/storage/model/typed_value_store.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "storage/model/typed_value_store.hpp"
|
||||
|
||||
const TypedValue& TypedValueStore::at(const TKey &key) const {
|
||||
for (const auto& kv : props_)
|
||||
if (kv.first == key)
|
||||
return kv.second;
|
||||
|
||||
return TypedValue::Null;
|
||||
}
|
||||
|
||||
template<typename TValue>
|
||||
void TypedValueStore::set(const TKey &key, const TValue &value) {
|
||||
for (auto& kv: props_)
|
||||
if (kv.first == key) {
|
||||
kv.second = TypedValue(value);
|
||||
return;
|
||||
}
|
||||
|
||||
// there is no value for the given key, add new
|
||||
// TODO consider vector size increment optimization
|
||||
props_.push_back(std::move(std::make_pair(key, value)));
|
||||
}
|
||||
|
||||
// instantiations of the TypedValueStore::set function
|
||||
// instances must be made for all of the supported C++ types
|
||||
template void TypedValueStore::set<std::string>(const TKey &key, const std::string &value);
|
||||
template void TypedValueStore::set<bool>(const TKey &key, const bool &value);
|
||||
template void TypedValueStore::set<int>(const TKey &key, const int &value);
|
||||
template void TypedValueStore::set<float>(const TKey &key, const float &value);
|
||||
|
||||
/**
|
||||
* Set overriding for character constants. Forces conversion
|
||||
* to std::string, otherwise templating might cast the pointer
|
||||
* to something else (bool) and mess things up.
|
||||
*
|
||||
* @param key The key for which the property is set. The previous
|
||||
* value at the same key (if there was one) is replaced.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
void TypedValueStore::set(const TKey &key, const char *value) {
|
||||
set(key, std::string(value));
|
||||
}
|
||||
|
||||
size_t TypedValueStore::erase(const TKey &key) {
|
||||
auto found = std::find_if(props_.begin(), props_.end(), [&key](std::pair<TKey, TypedValue> &kv){return kv.first == key;});
|
||||
if (found != props_.end()) {
|
||||
props_.erase(found);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t TypedValueStore::size() const { return props_.size(); }
|
||||
|
||||
void TypedValueStore::Accept(std::function<void(const TypedValueStore::TKey, const TypedValue &)> handler,
|
||||
std::function<void()> finish) const {
|
||||
if (handler)
|
||||
for (const auto& prop : props_)
|
||||
handler(prop.first, prop.second);
|
||||
|
||||
if (finish)
|
||||
finish();
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ int main()
|
||||
init_log();
|
||||
|
||||
memory_check(THREADS_NO, [] {
|
||||
set_t skiplist;
|
||||
ConcurrentSet<std::string> skiplist;
|
||||
|
||||
auto futures = run<std::vector<long>>(
|
||||
THREADS_NO, skiplist, [](auto acc, auto index) {
|
||||
@ -25,14 +25,16 @@ int main()
|
||||
std::vector<long> set(key_range);
|
||||
|
||||
do {
|
||||
size_t num = rand();
|
||||
int num = rand();
|
||||
std::string num_str = std::to_string(num);
|
||||
if (rand_op()) {
|
||||
if (acc.remove(num)) {
|
||||
if (acc.remove(num_str)) {
|
||||
downcount--;
|
||||
set[num]--;
|
||||
}
|
||||
} else {
|
||||
if (acc.insert(num).second) {
|
||||
std::string num_str = std::to_string(num);
|
||||
if (acc.insert(num_str).second) {
|
||||
downcount--;
|
||||
set[num]++;
|
||||
}
|
||||
@ -52,12 +54,12 @@ int main()
|
||||
auto accessor = skiplist.access();
|
||||
for (int i = 0; i < key_range; i++) {
|
||||
permanent_assert(set[i] == 0 || set[i] == 1 ||
|
||||
(set[i] == 1) ^ accessor.contains(i),
|
||||
(set[i] == 1) ^ accessor.contains(std::to_string(i)),
|
||||
"Set doesn't hold it's guarantees.");
|
||||
}
|
||||
|
||||
for (auto &e : accessor) {
|
||||
set[e]--;
|
||||
set[std::stoi(e)]--;
|
||||
}
|
||||
|
||||
check_zero(key_range, set, "Set");
|
||||
|
Loading…
Reference in New Issue
Block a user