summaryrefslogtreecommitdiff
path: root/src/value.hh
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2014-01-09 21:01:29 +0000
committerMaxime Coste <frrrwww@gmail.com>2014-01-09 21:01:29 +0000
commit85387b3efecec5e291a5ffaf20ab227f6094bd7b (patch)
treef5753dc53bb56f008fac8be0910a29feec27162b /src/value.hh
parente6884f989c2d955b8893d9b8eccc80f8cda0c7ca (diff)
Buffers can hold arbitrary values for for other systems
Diffstat (limited to 'src/value.hh')
-rw-r--r--src/value.hh118
1 files changed, 118 insertions, 0 deletions
diff --git a/src/value.hh b/src/value.hh
new file mode 100644
index 00000000..9122255a
--- /dev/null
+++ b/src/value.hh
@@ -0,0 +1,118 @@
+#ifndef value_hh_INCLUDED
+#define value_hh_INCLUDED
+
+#include <memory>
+#include <unordered_map>
+
+#include "units.hh"
+
+namespace Kakoune
+{
+
+struct bad_value_cast {};
+
+struct Value
+{
+ Value() = default;
+
+ template<typename T>
+ Value(const T& val) : m_value{new Model<T>{val}} {}
+
+ template<typename T>
+ Value(T&& val) : m_value{new Model<T>{std::move(val)}} {}
+
+ Value(const Value& val)
+ {
+ if (val.m_value)
+ m_value.reset(val.m_value->clone());
+ }
+
+ Value(Value&&) = default;
+
+ Value& operator=(const Value& val)
+ {
+ if (val.m_value)
+ m_value.reset(val.m_value->clone());
+ else
+ m_value.reset();
+ return *this;
+ }
+
+ 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() {}
+ virtual const std::type_info& type() const = 0;
+ virtual Concept* clone() const = 0;
+ };
+
+ template<typename T>
+ struct Model : public Concept
+ {
+ Model(const T& val) : m_content(val) {}
+ Model(T&& val) : m_content(std::move(val)) {}
+
+ const std::type_info& type() const override { return typeid(T); }
+ Concept* clone() const { return new Model(m_content); }
+
+ T m_content;
+ };
+
+ std::unique_ptr<Concept> m_value;
+};
+
+struct ValueId : public StronglyTypedNumber<ValueId, int>
+{
+ constexpr ValueId(int value = 0) : StronglyTypedNumber<ValueId>(value) {}
+
+ static ValueId get_free_id()
+ {
+ static ValueId next;
+ return next++;
+ }
+};
+
+using ValueMap = std::unordered_map<ValueId, Value>;
+
+}
+
+namespace std
+{
+
+template<>
+struct hash<Kakoune::ValueId>
+{
+ size_t operator()(Kakoune::ValueId val) const
+ {
+ return std::hash<int>()((int)val);
+ }
+};
+
+}
+
+
+#endif // value_hh_INCLUDED