kakoune/src/value.hh
2017-09-07 19:38:34 +08:00

84 lines
1.7 KiB
C++

#ifndef value_hh_INCLUDED
#define value_hh_INCLUDED
#include "hash_map.hh"
#include "units.hh"
#include <type_traits>
#include <memory>
namespace Kakoune
{
struct bad_value_cast {};
struct Value
{
Value() = default;
template<typename T,
typename = std::enable_if_t<not std::is_same<Value, T>::value>>
Value(T&& val)
: m_value{new Model<std::decay_t<T>>{std::forward<T>(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<typename T>
bool is_a() const
{
return m_value and m_value->type() == typeid(T);
}
template<typename T>
T& as()
{
if (not is_a<T>())
throw bad_value_cast{};
return static_cast<Model<T>*>(m_value.get())->m_content;
}
template<typename T>
const T& as() const
{
return const_cast<Value*>(this)->as<T>();
}
private:
struct Concept
{
virtual ~Concept() = default;
virtual const std::type_info& type() const = 0;
};
template<typename T>
struct Model : public Concept, public UseMemoryDomain<MemoryDomain::Values>
{
Model(T&& val) : m_content(std::move(val)) {}
const std::type_info& type() const override { return typeid(T); }
T m_content;
};
std::unique_ptr<Concept> m_value;
};
enum class ValueId : int {};
inline ValueId get_free_value_id()
{
static int next = 0;
return (ValueId)(next++);
}
using ValueMap = HashMap<ValueId, Value, MemoryDomain::Values>;
}
#endif // value_hh_INCLUDED