1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #pragma once |
4 | |
5 | #ifdef __BORLANDC__ |
6 | #define __STD_ALGORITHM |
7 | #endif |
8 | |
9 | #include <cassert> |
10 | #include <cstdio> |
11 | #include <cstdlib> |
12 | #include <ctime> |
13 | #include <cstring> |
14 | #include <cstdarg> |
15 | #include <cmath> |
16 | |
17 | #include <memory> |
18 | |
19 | // STL containers |
20 | #include <vector> |
21 | #include <stack> |
22 | #include <map> |
23 | #include <string> |
24 | #include <set> |
25 | #include <list> |
26 | #include <forward_list> |
27 | #include <deque> |
28 | #include <queue> |
29 | #include <bitset> |
30 | #include <array> |
31 | |
32 | #include <unordered_map> |
33 | #include <unordered_set> |
34 | |
35 | // STL algorithms & functions |
36 | #include <algorithm> |
37 | #include <functional> |
38 | #include <limits> |
39 | #include <iterator> |
40 | |
41 | // C++ Stream stuff |
42 | #include <fstream> |
43 | #include <iostream> |
44 | #include <iomanip> |
45 | #include <sstream> |
46 | |
47 | extern "C" { |
48 | |
49 | # include <sys/types.h> |
50 | # include <sys/stat.h> |
51 | |
52 | } |
53 | |
54 | #if BS_PLATFORM == BS_PLATFORM_WIN32 |
55 | # undef min |
56 | # undef max |
57 | # if !defined(NOMINMAX) && defined(_MSC_VER) |
58 | # define NOMINMAX // required to stop windows.h messing up std::min |
59 | # endif |
60 | # if defined( __MINGW32__ ) |
61 | # include <unistd.h> |
62 | # endif |
63 | #endif |
64 | |
65 | #if BS_PLATFORM == BS_PLATFORM_LINUX |
66 | extern "C" { |
67 | |
68 | # include <unistd.h> |
69 | # include <dlfcn.h> |
70 | |
71 | } |
72 | #endif |
73 | |
74 | #if BS_PLATFORM == BS_PLATFORM_OSX |
75 | extern "C" { |
76 | |
77 | # include <unistd.h> |
78 | # include <sys/param.h> |
79 | # include <CoreFoundation/CoreFoundation.h> |
80 | |
81 | } |
82 | #endif |
83 | |
84 | namespace bs |
85 | { |
86 | /** |
87 | * Hash for enum types, to be used instead of std::hash<T> when T is an enum. |
88 | * |
89 | * Until C++14, std::hash<T> is not defined if T is a enum (see |
90 | * http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2148). But |
91 | * even with C++14, as of october 2016, std::hash for enums is not widely |
92 | * implemented by compilers, so here when T is a enum, we use EnumClassHash |
93 | * instead of std::hash. (For instance, in bs::hash_combine(), or |
94 | * bs::UnorderedMap.) |
95 | */ |
96 | struct EnumClassHash |
97 | { |
98 | template <typename T> |
99 | constexpr std::size_t operator()(T t) const |
100 | { |
101 | return static_cast<std::size_t>(t); |
102 | } |
103 | }; |
104 | |
105 | /** @addtogroup Containers |
106 | * @{ |
107 | */ |
108 | |
109 | /** Hasher that handles custom enums automatically. */ |
110 | template <typename Key> |
111 | using HashType = typename std::conditional<std::is_enum<Key>::value, EnumClassHash, std::hash<Key>>::type; |
112 | |
113 | /** Double ended queue. Allows for fast insertion and removal at both its beggining and end. */ |
114 | template <typename T, typename A = StdAlloc<T>> |
115 | using Deque = std::deque<T, A>; |
116 | |
117 | /** Dynamically sized array that stores element contigously. */ |
118 | template <typename T, typename A = StdAlloc<T>> |
119 | using Vector = std::vector<T, A>; |
120 | |
121 | /** |
122 | * Container that supports constant time insertion and removal for elements with known locations, but without fast |
123 | * random access to elements. Internally implemented as a doubly linked list. Use ForwardList if you do not need |
124 | * reverse iteration. |
125 | */ |
126 | template <typename T, typename A = StdAlloc<T>> |
127 | using List = std::list<T, A>; |
128 | |
129 | /** |
130 | * Container that supports constant time insertion and removal for elements with known locations, but without fast |
131 | * random access to elements. Internally implemented as a singly linked list that doesn't support reverse iteration. |
132 | */ |
133 | template <typename T, typename A = StdAlloc<T>> |
134 | using ForwardList = std::forward_list<T, A>; |
135 | |
136 | /** First-in, last-out data structure. */ |
137 | template <typename T, typename A = StdAlloc<T>> |
138 | using Stack = std::stack<T, std::deque<T, A>>; |
139 | |
140 | /** First-in, first-out data structure. */ |
141 | template <typename T, typename A = StdAlloc<T>> |
142 | using Queue = std::queue<T, std::deque<T, A>>; |
143 | |
144 | /** An associative container containing an ordered set of elements. */ |
145 | template <typename T, typename P = std::less<T>, typename A = StdAlloc<T>> |
146 | using Set = std::set<T, P, A>; |
147 | |
148 | /** An associative container containing an ordered set of key-value pairs. */ |
149 | template <typename K, typename V, typename P = std::less<K>, typename A = StdAlloc<std::pair<const K, V>>> |
150 | using Map = std::map<K, V, P, A>; |
151 | |
152 | /** An associative container containing an ordered set of elements where multiple elements can have the same key. */ |
153 | template <typename T, typename P = std::less<T>, typename A = StdAlloc<T>> |
154 | using MultiSet = std::multiset<T, P, A>; |
155 | |
156 | /** An associative container containing an ordered set of key-value pairs where multiple elements can have the same key. */ |
157 | template <typename K, typename V, typename P = std::less<K>, typename A = StdAlloc<std::pair<const K, V>>> |
158 | using MultiMap = std::multimap<K, V, P, A>; |
159 | |
160 | /** An associative container containing an unordered set of elements. Usually faster than Set for larger data sets. */ |
161 | template <typename T, typename H = HashType<T>, typename C = std::equal_to<T>, typename A = StdAlloc<T>> |
162 | using UnorderedSet = std::unordered_set<T, H, C, A>; |
163 | |
164 | /** An associative container containing an ordered set of key-value pairs. Usually faster than Map for larger data sets. */ |
165 | template <typename K, typename V, typename H = HashType<K>, typename C = std::equal_to<K>, typename A = StdAlloc<std::pair<const K, V>>> |
166 | using UnorderedMap = std::unordered_map<K, V, H, C, A>; |
167 | |
168 | /** |
169 | * An associative container containing an ordered set of key-value pairs where multiple elements can have the same key. |
170 | * Usually faster than MultiMap for larger data sets. |
171 | */ |
172 | template <typename K, typename V, typename H = HashType<K>, typename C = std::equal_to<K>, typename A = StdAlloc<std::pair<const K, V>>> |
173 | using UnorderedMultimap = std::unordered_multimap<K, V, H, C, A>; |
174 | |
175 | /** @} */ |
176 | |
177 | /** @addtogroup Memory |
178 | * @{ |
179 | */ |
180 | |
181 | /** |
182 | * Smart pointer that retains shared ownership of an project through a pointer. The object is destroyed automatically |
183 | * when the last shared pointer to the object is destroyed. |
184 | */ |
185 | template <typename T> |
186 | using SPtr = std::shared_ptr<T>; |
187 | |
188 | /** Holds a reference to an object whose lifetime is managed by a SPtr, but doesn't increment the reference count. */ |
189 | template <typename T> |
190 | using WeakSPtr = std::weak_ptr<T>; |
191 | |
192 | /** |
193 | * Smart pointer that retains shared ownership of an project through a pointer. Reference to the object must be unique. |
194 | * The object is destroyed automatically when the pointer to the object is destroyed. |
195 | */ |
196 | template <typename T, typename Alloc = GenAlloc, typename Delete = Deleter<T, Alloc>> |
197 | using UPtr = std::unique_ptr<T, Delete>; |
198 | |
199 | /** Create a new shared pointer using a custom allocator category. */ |
200 | template<typename Type, typename AllocCategory = GenAlloc, typename... Args> |
201 | SPtr<Type> bs_shared_ptr_new(Args &&... args) |
202 | { |
203 | return std::allocate_shared<Type>(StdAlloc<Type, AllocCategory>(), std::forward<Args>(args)...); |
204 | } |
205 | |
206 | /** |
207 | * Create a new shared pointer from a previously constructed object. |
208 | * Pointer specific data will be allocated using the provided allocator category. |
209 | */ |
210 | template<typename Type, typename MainAlloc = GenAlloc, typename PtrDataAlloc = GenAlloc, typename Delete = Deleter<Type, MainAlloc>> |
211 | SPtr<Type> bs_shared_ptr(Type* data, Delete del = Delete()) |
212 | { |
213 | return SPtr<Type>(data, std::move(del), StdAlloc<Type, PtrDataAlloc>()); |
214 | } |
215 | |
216 | /** |
217 | * Create a new unique pointer from a previously constructed object. |
218 | * Pointer specific data will be allocated using the provided allocator category. |
219 | */ |
220 | template<typename Type, typename Alloc = GenAlloc, typename Delete = Deleter<Type, Alloc>> |
221 | UPtr<Type, Alloc, Delete> bs_unique_ptr(Type* data, Delete del = Delete()) |
222 | { |
223 | return std::unique_ptr<Type, Delete>(data, std::move(del)); |
224 | } |
225 | |
226 | /** Create a new unique pointer using a custom allocator category. */ |
227 | template<typename Type, typename Alloc = GenAlloc, typename Delete = Deleter<Type, Alloc>, typename... Args> |
228 | UPtr<Type, Alloc, Delete> bs_unique_ptr_new(Args &&... args) |
229 | { |
230 | Type* rawPtr = bs_new<Type, Alloc>(std::forward<Args>(args)...); |
231 | |
232 | return bs_unique_ptr<Type, Alloc, Delete>(rawPtr); |
233 | } |
234 | |
235 | /** |
236 | * "Smart" pointer that is not smart. Does nothing but hold a pointer value. No memory management is performed at all. |
237 | * This class exists to make storing pointers in containers easier to manage, such as with non-member comparison |
238 | * operators. |
239 | */ |
240 | template<typename T> |
241 | struct NativePtr |
242 | { |
243 | constexpr NativePtr(T* p) : mPtr(p) {} |
244 | constexpr T& operator*() const { return *mPtr; } |
245 | constexpr T* operator->() const { return mPtr; } |
246 | constexpr T* get() const { return mPtr; } |
247 | |
248 | private: |
249 | T* mPtr = nullptr; |
250 | }; |
251 | |
252 | template<typename T> |
253 | using NPtr = NativePtr<T>; |
254 | |
255 | template<typename L_T, typename R_T> |
256 | constexpr bool operator< (const NPtr<L_T>& lhs, const NPtr<R_T>& rhs) |
257 | { |
258 | return lhs.get() < rhs.get(); |
259 | } |
260 | |
261 | template<typename L_T, typename R_T> |
262 | constexpr bool operator> (const NPtr<L_T>& lhs, const NPtr<R_T>& rhs) |
263 | { |
264 | return lhs.get() > rhs.get(); |
265 | } |
266 | |
267 | template<typename L_T, typename R_T> |
268 | constexpr bool operator<= (const NPtr<L_T>& lhs, const NPtr<R_T>& rhs) |
269 | { |
270 | return lhs.get() <= rhs.get(); |
271 | } |
272 | |
273 | template<typename L_T, typename R_T> |
274 | constexpr bool operator>= (const NPtr<L_T>& lhs, const NPtr<R_T>& rhs) |
275 | { |
276 | return lhs.get() >= rhs.get(); |
277 | } |
278 | |
279 | template<typename L_T, typename R_T> |
280 | constexpr bool operator== (const NPtr<L_T>& lhs, const NPtr<R_T>& rhs) |
281 | { |
282 | return lhs.get() == rhs.get(); |
283 | } |
284 | |
285 | template<typename L_T, typename R_T> |
286 | constexpr bool operator!= (const NPtr<L_T>& lhs, const NPtr<R_T>& rhs) |
287 | { |
288 | return lhs.get() != rhs.get(); |
289 | } |
290 | |
291 | /** @} */ |
292 | } |
293 | |