#ifndef value_hh_INCLUDED #define value_hh_INCLUDED #include "unordered_map.hh" #include "units.hh" #include namespace Kakoune { struct bad_value_cast {}; struct Value { Value() = default; template Value(T&& val) : m_value{new Model{std::forward(val)}} {} Value(const Value& val) = delete; Value(Value&&) = default; Value& operator=(const Value& val) = delete; Value& operator=(Value&& val) = default; explicit operator bool() const { return (bool)m_value; } template bool is_a() const { return m_value and m_value->type() == typeid(T); } template T& as() { if (not is_a()) throw bad_value_cast{}; return static_cast*>(m_value.get())->m_content; } template const T& as() const { return const_cast(this)->as(); } private: struct Concept { virtual ~Concept() {} virtual const std::type_info& type() const = 0; }; template struct Model : public Concept { Model(T&& val) : m_content(std::move(val)) {} const std::type_info& type() const override { return typeid(T); } T m_content; using Alloc = Allocator, MemoryDomain::Values>; static void* operator new (std::size_t sz) { return Alloc{}.allocate(1); } static void operator delete (void* ptr) { Alloc{}.deallocate((Model*)ptr, 1); } }; std::unique_ptr m_value; }; struct ValueId : public StronglyTypedNumber { constexpr ValueId(int value = 0) : StronglyTypedNumber(value) {} static ValueId get_free_id() { static ValueId next; return next++; } }; inline size_t hash_value(ValueId val) { return hash_value((int)val); } using ValueMap = UnorderedMap; } #endif // value_hh_INCLUDED