From 6930b27d1f65c813753a42ca1f21e8e6a632a584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Tomic=CC=8Cevic=CC=81?= <dominik.tomicevic@gmail.com> Date: Tue, 13 Oct 2015 20:17:45 +0200 Subject: [PATCH] updated properties --- proptest.cpp | 120 ++++++++++++++++++ speedy/http/response.inl | 2 +- speedy/http/status_codes.hpp | 12 +- storage/model/properties/properties.hpp | 38 +++--- storage/model/properties/property.hpp | 158 ++++++++++++++++++++---- storage/model/properties/string.hpp | 22 ---- utils/underlying_cast.hpp | 12 ++ 7 files changed, 296 insertions(+), 68 deletions(-) create mode 100644 proptest.cpp delete mode 100644 storage/model/properties/string.hpp create mode 100644 utils/underlying_cast.hpp diff --git a/proptest.cpp b/proptest.cpp new file mode 100644 index 000000000..819c6bc97 --- /dev/null +++ b/proptest.cpp @@ -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; +} diff --git a/speedy/http/response.inl b/speedy/http/response.inl index e7e541ae7..32524ceda 100644 --- a/speedy/http/response.inl +++ b/speedy/http/response.inl @@ -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"; diff --git a/speedy/http/status_codes.hpp b/speedy/http/status_codes.hpp index dc3a4ca9d..b969dc1cc 100644 --- a/speedy/http/status_codes.hpp +++ b/speedy/http/status_codes.hpp @@ -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 -}; + } +} } diff --git a/storage/model/properties/properties.hpp b/storage/model/properties/properties.hpp index 36347a5b6..e60955b1f 100644 --- a/storage/model/properties/properties.hpp +++ b/storage/model/properties/properties.hpp @@ -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 diff --git a/storage/model/properties/property.hpp b/storage/model/properties/property.hpp index 61174225a..09114ae1c 100644 --- a/storage/model/properties/property.hpp +++ b/storage/model/properties/property.hpp @@ -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 diff --git a/storage/model/properties/string.hpp b/storage/model/properties/string.hpp deleted file mode 100644 index 49bb82d50..000000000 --- a/storage/model/properties/string.hpp +++ /dev/null @@ -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 diff --git a/utils/underlying_cast.hpp b/utils/underlying_cast.hpp new file mode 100644 index 000000000..7b8f1ae17 --- /dev/null +++ b/utils/underlying_cast.hpp @@ -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