#ifndef utils_hh_INCLUDED #define utils_hh_INCLUDED #include "assert.hh" #include "exception.hh" #include #include #include #include namespace Kakoune { // *** Singleton *** // // Singleton helper class, every singleton type T should inherit // from Singleton to provide a consistent interface. template class Singleton { public: Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; static T& instance() { kak_assert (ms_instance); return *ms_instance; } static bool has_instance() { return ms_instance != nullptr; } protected: Singleton() { kak_assert(not ms_instance); ms_instance = static_cast(this); } ~Singleton() { kak_assert(ms_instance == this); ms_instance = nullptr; } private: static T* ms_instance; }; template T* Singleton::ms_instance = nullptr; // *** Containers helpers *** template struct ReversedContainer { ReversedContainer(Container& container) : container(container) {} Container& container; decltype(container.rbegin()) begin() { return container.rbegin(); } decltype(container.rend()) end() { return container.rend(); } }; template auto begin(ReversedContainer& c) -> decltype(c.begin()) { return c.begin(); } template auto end(ReversedContainer& c) -> decltype(c.end()) { return c.end(); } template ReversedContainer reversed(Container&& container) { return ReversedContainer(container); } template auto find(Container&& container, const T& value) -> decltype(begin(container)) { return std::find(begin(container), end(container), value); } template auto find_if(Container&& container, T op) -> decltype(begin(container)) { return std::find_if(begin(container), end(container), op); } template bool contains(Container&& container, const T& value) { return find(container, value) != end(container); } template bool contains(const std::unordered_set& container, const T2& value) { return container.find(value) != container.end(); } template void skip_while(Iterator& it, const EndIterator& end, T condition) { while (it != end and condition(*it)) ++it; } template void skip_while_reverse(Iterator& it, const BeginIterator& begin, T condition) { while (it != begin and condition(*it)) --it; } // *** On scope end *** // // on_scope_end provides a way to register some code to be // executed when current scope closes. // // usage: // auto cleaner = on_scope_end([]() { ... }); // // This permits to cleanup c-style resources without implementing // a wrapping class template class OnScopeEnd { public: OnScopeEnd(T func) : m_func(std::move(func)) {} ~OnScopeEnd() { m_func(); } private: T m_func; }; template OnScopeEnd on_scope_end(T t) { return OnScopeEnd(t); } // *** Misc helper functions *** template bool operator== (const std::unique_ptr& lhs, T* rhs) { return lhs.get() == rhs; } template const T& clamp(const T& val, const T& min, const T& max) { return (val < min ? min : (val > max ? max : val)); } template bool is_in_range(const T& val, const T& min, const T& max) { return min <= val and val <= max; } // *** AutoRegister: RAII handling of value semantics registering classes *** template class AutoRegister { public: AutoRegister(Registry& registry) : m_registry(®istry) { RegisterFuncs::insert(*m_registry, effective_this()); } AutoRegister(const AutoRegister& other) : m_registry(other.m_registry) { RegisterFuncs::insert(*m_registry, effective_this()); } AutoRegister(AutoRegister&& other) : m_registry(other.m_registry) { RegisterFuncs::insert(*m_registry, effective_this()); } ~AutoRegister() { RegisterFuncs::remove(*m_registry, effective_this()); } AutoRegister& operator=(const AutoRegister& other) { if (m_registry != other.m_registry) { RegisterFuncs::remove(*m_registry, effective_this()); m_registry = other.m_registry; RegisterFuncs::insert(*m_registry, effective_this()); } return *this; } AutoRegister& operator=(AutoRegister&& other) { if (m_registry != other.m_registry) { RegisterFuncs::remove(*m_registry, effective_this()); m_registry = other.m_registry; RegisterFuncs::insert(*m_registry, effective_this()); } return *this; } Registry& registry() const { return *m_registry; } private: EffectiveType& effective_this() { return static_cast(*this); } Registry* m_registry; }; } // std::pair hashing namespace std { template struct hash> { size_t operator()(const std::pair& val) const { size_t seed = std::hash()(val.second); return seed ^ (std::hash()(val.first) + 0x9e3779b9 + (seed << 6) + (seed >> 2)); } }; } #endif // utils_hh_INCLUDED