1 #ifndef utils_hh_INCLUDED
2 #define utils_hh_INCLUDED
3 
4 #include "assert.hh"
5 
6 #include <memory>
7 
8 namespace Kakoune
9 {
10 
11 // *** Singleton ***
12 //
13 // Singleton helper class, every singleton type T should inherit
14 // from Singleton<T> to provide a consistent interface.
15 template<typename T>
16 class Singleton
17 {
18 public:
19     Singleton(const Singleton&) = delete;
20     Singleton& operator=(const Singleton&) = delete;
21 
instance()22     static T& instance()
23     {
24         kak_assert(ms_instance);
25         return *static_cast<T*>(ms_instance);
26     }
27 
has_instance()28     static bool has_instance()
29     {
30         return ms_instance != nullptr;
31     }
32 
33 protected:
Singleton()34     Singleton()
35     {
36         kak_assert(ms_instance == nullptr);
37         ms_instance = this;
38     }
39 
~Singleton()40     ~Singleton()
41     {
42         kak_assert(ms_instance == this);
43         ms_instance = nullptr;
44     }
45 
46 private:
47     static Singleton* ms_instance;
48 };
49 
50 template<typename T>
51 Singleton<T>* Singleton<T>::ms_instance = nullptr;
52 
53 // *** On scope end ***
54 //
55 // on_scope_end provides a way to register some code to be
56 // executed when current scope closes.
57 //
58 // usage:
59 // auto cleaner = on_scope_end([]() { ... });
60 //
61 // This permits to cleanup c-style resources without implementing
62 // a wrapping class
63 template<typename T>
64 class [[nodiscard]] OnScopeEnd
65 {
66 public:
67     [[gnu::always_inline]]
OnScopeEnd(T func)68     OnScopeEnd(T func) : m_valid{true}, m_func{std::move(func)} {}
69 
70     [[gnu::always_inline]]
OnScopeEnd(OnScopeEnd && other)71     OnScopeEnd(OnScopeEnd&& other)
72       : m_valid{other.m_valid}, m_func{std::move(other.m_func)}
73     { other.m_valid = false; }
74 
75     [[gnu::always_inline]]
~OnScopeEnd()76     ~OnScopeEnd() noexcept(noexcept(std::declval<T>()())) { if (m_valid) m_func(); }
77 
78 private:
79     bool m_valid;
80     T m_func;
81 };
82 
83 template<typename T>
on_scope_end(T t)84 OnScopeEnd<T> on_scope_end(T t)
85 {
86     return OnScopeEnd<T>{std::move(t)};
87 }
88 
89 // bool that can be set (to true) multiple times, and will
90 // be false only when unset the same time;
91 struct NestedBool
92 {
setKakoune::NestedBool93     void set() { m_count++; }
unsetKakoune::NestedBool94     void unset() { kak_assert(m_count > 0); m_count--; }
95 
operator boolKakoune::NestedBool96     operator bool() const { return m_count > 0; }
97 private:
98     int m_count = 0;
99 };
100 
101 struct ScopedSetBool
102 {
ScopedSetBoolKakoune::ScopedSetBool103     ScopedSetBool(NestedBool& nested_bool, bool condition = true)
104         : m_nested_bool(nested_bool), m_condition(condition)
105     {
106         if (m_condition)
107             m_nested_bool.set();
108     }
109 
ScopedSetBoolKakoune::ScopedSetBool110     ScopedSetBool(ScopedSetBool&& other)
111         : m_nested_bool(other.m_nested_bool), m_condition(other.m_condition)
112     {
113         other.m_condition = false;
114     }
115 
~ScopedSetBoolKakoune::ScopedSetBool116     ~ScopedSetBool()
117     {
118         if (m_condition)
119             m_nested_bool.unset();
120     }
121 
122 private:
123     NestedBool& m_nested_bool;
124     bool m_condition;
125 };
126 
127 // *** Misc helper functions ***
128 
129 template<typename T>
operator ==(const std::unique_ptr<T> & lhs,T * rhs)130 bool operator== (const std::unique_ptr<T>& lhs, T* rhs)
131 {
132     return lhs.get() == rhs;
133 }
134 
135 template<typename T>
clamp(const T & val,const T & min,const T & max)136 const T& clamp(const T& val, const T& min, const T& max)
137 {
138     return (val < min ? min : (val > max ? max : val));
139 }
140 
141 template<typename Iterator, typename EndIterator, typename T>
skip_while(Iterator & it,const EndIterator & end,T condition)142 bool skip_while(Iterator& it, const EndIterator& end, T condition)
143 {
144     while (it != end and condition(*it))
145         ++it;
146     return it != end;
147 }
148 
149 template<typename Iterator, typename BeginIterator, typename T>
skip_while_reverse(Iterator & it,const BeginIterator & begin,T condition)150 bool skip_while_reverse(Iterator& it, const BeginIterator& begin, T condition)
151 {
152     while (it != begin and condition(*it))
153         --it;
154     return condition(*it);
155 }
156 
157 template<typename E>
to_underlying(E value)158 auto to_underlying(E value)
159 {
160     return static_cast<std::underlying_type_t<E>>(value);
161 }
162 
163 template<typename> class FunctionRef;
164 
165 template<typename Res, typename... Args>
166 class FunctionRef<Res(Args...)>
167 {
168 public:
FunctionRef()169     FunctionRef()
170       : m_target{nullptr},
__anonf252be6b0102() 171         m_invoker{[](void* target, Args... args) {
172             if constexpr (!std::is_same_v<Res, void>) return Res{};
173         }}
174     {}
175 
176     template<typename Target,
177              typename = std::enable_if_t<
178                  not std::is_same_v<FunctionRef, std::decay_t<Target>> and
179                  std::is_convertible_v<decltype(std::declval<Target>()(std::declval<Args>()...)), Res>
180              >>
FunctionRef(Target && target)181     FunctionRef(Target&& target)
182       : m_target{&target},
__anonf252be6b0202() 183         m_invoker{[](void* target, Args... args) {
184             return (*reinterpret_cast<Target*>(target))(static_cast<Args>(args)...);
185         }}
186     {}
187 
operator ()(Args...args) const188     Res operator()(Args... args) const
189     {
190         return m_invoker(m_target, static_cast<Args>(args)...);
191     }
192 
193 private:
194     using Invoker = Res (void*, Args...);
195     void* m_target;
196     Invoker* m_invoker;
197 };
198 
199 template<typename... Funcs>
200 struct Overload : Funcs...
201 {
202     using Funcs::operator()...;
203 };
204 
205 template<typename... Funcs>
overload(Funcs &&...funcs)206 auto overload(Funcs&&... funcs)
207 {
208     return Overload<std::decay_t<Funcs>...>{std::forward<Funcs>(funcs)...};
209 }
210 
211 }
212 
213 #endif // utils_hh_INCLUDED
214