diff options
| author | Maxime Coste <frrrwww@gmail.com> | 2014-01-09 21:01:29 +0000 |
|---|---|---|
| committer | Maxime Coste <frrrwww@gmail.com> | 2014-01-09 21:01:29 +0000 |
| commit | 85387b3efecec5e291a5ffaf20ab227f6094bd7b (patch) | |
| tree | f5753dc53bb56f008fac8be0910a29feec27162b /src | |
| parent | e6884f989c2d955b8893d9b8eccc80f8cda0c7ca (diff) | |
Buffers can hold arbitrary values for for other systems
Diffstat (limited to 'src')
| -rw-r--r-- | src/buffer.hh | 7 | ||||
| -rw-r--r-- | src/value.hh | 118 |
2 files changed, 125 insertions, 0 deletions
diff --git a/src/buffer.hh b/src/buffer.hh index 9c648625..17de0f07 100644 --- a/src/buffer.hh +++ b/src/buffer.hh @@ -6,6 +6,7 @@ #include "option_manager.hh" #include "keymap_manager.hh" #include "string.hh" +#include "value.hh" #include <vector> #include <list> @@ -166,6 +167,8 @@ public: KeymapManager& keymaps() { return m_keymaps; } const KeymapManager& keymaps() const { return m_keymaps; } + ValueMap& values() const { return m_values; } + void run_hook_in_own_context(const String& hook_name, const String& param); std::unordered_set<BufferChangeListener*>& change_listeners() const { return m_change_listeners; } @@ -224,6 +227,10 @@ private: HookManager m_hooks; KeymapManager m_keymaps; + // Values are just data holding by the buffer, so it is part of its + // observable state + mutable ValueMap m_values; + friend constexpr Flags operator|(Flags lhs, Flags rhs) { return (Flags)((int) lhs | (int) rhs); 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 |
