updated properties

This commit is contained in:
Dominik Tomičević 2015-10-13 20:17:45 +02:00
parent 0effba90d9
commit 6930b27d1f
7 changed files with 296 additions and 68 deletions

120
proptest.cpp Normal file
View File

@ -0,0 +1,120 @@
#include <iostream>
#include "storage/model/properties/properties.hpp"
#include "storage/model/properties/property.hpp"
template <class Buffer>
struct JsonWriter
{
public:
JsonWriter(Buffer& buffer) : buffer(buffer)
{
buffer << '{';
};
void handle(const std::string& key, Property& value, bool first)
{
if(!first)
buffer << ',';
buffer << '"' << key << "\":";
value.accept(*this);
}
void handle(Null&)
{
buffer << "NULL";
}
void handle(Bool& b)
{
buffer << (b.value() ? "true" : "false");
}
void handle(String& s)
{
buffer << '"' << s.value << '"';
}
void handle(Int32& int32)
{
buffer << std::to_string(int32.value);
}
void handle(Int64& int64)
{
buffer << std::to_string(int64.value);
}
void handle(Float& f)
{
buffer << std::to_string(f.value);
}
void handle(Double& d)
{
buffer << std::to_string(d.value);
}
void finish()
{
buffer << '}';
}
private:
Buffer& buffer;
};
class StringBuffer
{
public:
StringBuffer& operator<<(const std::string& str)
{
data += str;
return *this;
}
StringBuffer& operator<<(const char* str)
{
data += str;
return *this;
}
StringBuffer& operator<<(char c)
{
data += c;
return *this;
}
std::string& str()
{
return data;
}
private:
std::string data;
};
int main(void)
{
StringBuffer buffer;
auto handler = JsonWriter<StringBuffer>(buffer);
Properties props;
props.emplace<Null>("sadness");
props.emplace<Bool>("awesome", true);
props.emplace<Bool>("lame", false);
props.emplace<Int32>("age", 32);
props.emplace<Int64>("money", 12345678910111213);
props.emplace<String>("name", "caca");
props.emplace<Float>("pi", 3.14159265358979323846264338327950288419716939937510582097);
props.emplace<Double>("pi2", 3.141592653589793238462643383279502884197169399375105820);
props.accept(handler);
handler.finish();
std::cout.precision(25);
std::cout << buffer.str() << std::endl;
return 0;
}

View File

@ -30,7 +30,7 @@ void Response<Req, Res>::send(const std::string& body)
write_req->data = &connection;
buffer << "HTTP/1.1 " << to_string[status] << "\r\n";
buffer << "HTTP/1.1 " << to_string(status) << "\r\n";
buffer << "Content-Length:" << std::to_string(body.size()) << "\r\n";

View File

@ -72,11 +72,15 @@ enum Status
#undef CODE
};
static std::map<Status, std::string> to_string = {
#define CODE(a, b, c) { Status::a, #b " " #c },
HTTP_STATUS_CODES
std::string to_string(Status status)
{
switch(status)
{
#define CODE(a, b, c) case a: return #b " " #c;
HTTP_STATUS_CODES
#undef CODE
};
}
}
}

View File

@ -4,10 +4,6 @@
#include <map>
#include "property.hpp"
#include "string.hpp"
namespace model
{
class Properties
{
@ -25,6 +21,22 @@ public:
return it == props.end() ? nullptr : it->second.get();
}
template <class T, class... Args>
void emplace(const std::string& key, Args&&... args)
{
auto value = std::make_shared<T>(std::forward<Args>(args)...);
// try to emplace the item
auto result = props.emplace(std::make_pair(key, std::move(value)));
// return if we succedded
if(result.second)
return;
// the key already exists, replace the value it holds
result.first->second = std::move(value);
}
void put(const std::string& key, Property::sptr value)
{
props[key] = std::move(value);
@ -35,24 +47,22 @@ public:
props.erase(key);
}
void dump(std::string& buffer)
template <class Handler>
void accept(Handler& handler)
{
buffer += '{';
bool first = true;
for(auto& kvp : props)
for(auto& kv : props)
{
buffer += '"'; buffer += kvp.first; buffer += "\":";
kvp.second->dump(buffer); buffer += ',';
handler.handle(kv.first, *kv.second, first);
if(first)
first = false;
}
// replace last redundant comma with }
buffer.back() = '}';
}
private:
props_t props;
};
}
#endif

View File

@ -4,52 +4,156 @@
#include <memory>
#include <string>
namespace model
{
#include "utils/underlying_cast.hpp"
class Property
struct Property
{
public:
using sptr = std::shared_ptr<Property>;
template <class T, class... Args>
static Property::sptr make(Args&&... args)
enum class Flags : unsigned
{
return std::shared_ptr<Property>(new T(std::forward<Args>(args)...));
Null = 0x1,
Bool = 0x2,
True = 0x4 | Bool,
False = 0x8 | Bool,
String = 0x10,
Number = 0x20,
Integral = 0x40 | Number,
Int32 = 0x80 | Integral,
Int64 = 0x100 | Integral,
Floating = 0x200 | Number,
Float = 0x400 | Floating,
Double = 0x800 | Floating,
Array = 0x1000,
type_mask = 0xFFF
};
Property(Flags flags) : flags(flags) {}
Property(const Property&) = default;
template <class T>
T* is()
{
return underlying_cast(flags) & T::type;
}
Property() = default;
virtual ~Property() = default;
virtual void dump(std::string& buffer) = 0;
template <class T>
T* as()
{
// return dynamic_cast<T*>(this);
// http://stackoverflow.com/questions/579887/how-expensive-is-rtti
// so... typeid is 20x faster! but there are some caveats, use with
// caution. read CAREFULLY what those people are saying.
// should be ok to use in this situation because all types used by
// this comparison are local and compile together with this code
// and we're compiling it only for linux with gcc/clang and we will
// not use any classes from third party libraries in this function.
if(typeid(T*) == typeid(this))
if(this->is<T>())
return static_cast<T*>(this);
return nullptr;
}
template <class Handler>
void accept(Handler& handler);
Flags flags;
};
template <class T>
class Value : public Property
struct Null : public Property
{
public:
Value(T value) : value(value) {}
T value;
static constexpr Flags type = Flags::Null;
Null() : Property(Flags::Null) {}
bool is_null()
{
return true;
}
};
struct Bool : public Property
{
static constexpr Flags type = Flags::Bool;
Bool(bool value) : Property(value ? Flags::True : Flags::False) {}
bool value()
{
unsigned flags = underlying_cast(this->flags);
unsigned true_t = underlying_cast(Flags::True);
return (flags - true_t) == 0;
}
};
struct String : public Property
{
static constexpr Flags type = Flags::String;
String(const std::string& value)
: Property(Flags::String), value(value) {}
String(std::string&& value)
: Property(Flags::String), value(value) {}
std::string value;
};
struct Int32 : public Property
{
static constexpr Flags type = Flags::Int32;
Int32(int32_t value)
: Property(Flags::Int32), value(value) {}
int32_t value;
};
struct Int64 : public Property
{
static constexpr Flags type = Flags::Int64;
Int64(int64_t value)
: Property(Flags::Int64), value(value) {}
int64_t value;
};
struct Float : public Property
{
static constexpr Flags type = Flags::Float;
Float(float value)
: Property(Flags::Float), value(value) {}
float value;
};
struct Double : public Property
{
static constexpr Flags type = Flags::Double;
Double(double value)
: Property(Flags::Double), value(value) {}
double value;
};
template <class Handler>
void Property::accept(Handler& h)
{
switch(flags)
{
case Flags::Null: return h.handle(static_cast<Null&>(*this));
case Flags::True: return h.handle(static_cast<Bool&>(*this));
case Flags::False: return h.handle(static_cast<Bool&>(*this));
case Flags::String: return h.handle(static_cast<String&>(*this));
case Flags::Int32: return h.handle(static_cast<Int32&>(*this));
case Flags::Int64: return h.handle(static_cast<Int64&>(*this));
case Flags::Float: return h.handle(static_cast<Float&>(*this));
case Flags::Double: return h.handle(static_cast<Double&>(*this));
default: return;
}
}
#endif

View File

@ -1,22 +0,0 @@
#ifndef MEMGRAPH_STORAGE_MODEL_PROPERTIES_STRING_HPP
#define MEMGRAPH_STORAGE_MODEL_PROPERTIES_STRING_HPP
#include "property.hpp"
namespace model
{
class String : public Value<std::string>
{
public:
using Value::Value;
void dump(std::string& buffer) override
{
buffer += '"'; buffer += value; buffer += '"';
}
};
}
#endif

12
utils/underlying_cast.hpp Normal file
View File

@ -0,0 +1,12 @@
#ifndef MEMGRAPH_UTILS_UNDERLYING_CAST_HPP
#define MEMGRAPH_UTILS_UNDERLYING_CAST_HPP
#include <type_traits>
template <typename T>
constexpr typename std::underlying_type<T>::type underlying_cast(T e) {
return static_cast<typename std::underlying_type<T>::type>(e);
}
#endif