Foundation
Loading...
Searching...
No Matches
Container.hpp
Go to the documentation of this file.
1#pragma once
2#include <algorithm>
3#include <array>
4#include <bitset>
5#include <functional>
6#include <list>
7#include <map>
8#include <numeric>
9#include <optional>
10#include <queue>
11#include <ranges>
12#include <set>
13#include <span>
14#include <string>
15#include <string_view>
16#include <unordered_map>
17#include <unordered_set>
18#include <variant>
19#include <vector>
20#include <stack>
21
22#include "Allocator.hpp"
23#include "Hash.hpp"
24#include "Logging.hpp"
25namespace Foundation::Core
26{
27
28 /* -- STL Value types -- */
32 template <typename First, typename Second>
33 using Pair = std::pair<First, Second>;
34
38 template <typename... Args>
39 using Tuple = std::tuple<Args...>;
40
44 template <typename T, size_t Size>
45 using Array = std::array<T, Size>;
46
50 template <size_t Size>
51 using Bitset = std::bitset<Size>;
52
56 using StringView = std::basic_string_view<char>;
57
61 template <typename T>
62 using Span = std::span<T>;
63
64 template <typename T>
66 {
67 return {reinterpret_cast<const char*>(data.data()), data.size_bytes()};
68 }
72 template <typename T>
73 Span<const T> AsSpan(T const& data)
74 requires std::is_trivially_copyable_v<T>
75 {
76 return {&data, 1};
77 }
85 template <typename T, typename... Args>
86 Span<T> ConstructSpan(Allocator* resource, size_t size, Args&&... args)
87 {
88 T* data = static_cast<T*>(resource->Allocate(size * sizeof(T), alignof(T)));
89 if constexpr (!std::is_trivially_constructible_v<T> || sizeof...(Args) > 0)
90 {
91 for (size_t i = 0; i < size; i++)
92 std::construct_at(&data[i], std::forward<Args>(args)...);
93 }
94 return Span<T>(data, size);
95 }
100 template <typename T>
101 void DestructSpan(Allocator* resource, Span<T> span)
102 {
103 if constexpr (!std::is_trivially_destructible_v<T>)
104 {
105 for (T& item : span)
106 std::destroy_at(&item);
107 }
108 resource->Deallocate(span.data());
109 }
110 /* -- STL Containers -- */
111
120 using String = std::basic_string<char, std::char_traits<char>, StlDefaultAllocator<char>>;
125 template <typename... Args>
126 [[nodiscard]] constexpr String Format(fmt::format_string<Args...> format, Args&&... args)
127 {
128 fmt::basic_memory_buffer<char, fmt::inline_buffer_size, StlDefaultAllocator<char>> buffer;
129 fmt::format_to(std::back_inserter(buffer), format, std::forward<Args>(args)...);
130 return String(buffer.data(), buffer.size());
131 }
139 using StringAlloc = std::basic_string<char, std::char_traits<char>, StlAllocator<char>>;
140
148 template <typename T>
149 using Vector = std::vector<T, StlAllocator<T>>;
157 template <typename T, typename Predicate = std::less<T>>
158 using Set = std::set<T, Predicate, StlAllocator<T>>;
159
167 template <typename T, typename Predicate = std::less<T>>
168 using MultiSet = std::multiset<T, Predicate, StlAllocator<T>>;
169
177 template <typename K, typename V, typename Predicate = std::less<K>>
178 using Map = std::map<K, V, Predicate, StlAllocator<Pair<const K, V>>>;
179
185 template <typename K, typename V, typename Hash = std::hash<K>, typename KeyEq = std::equal_to<K>>
186 using HashMap = std::unordered_map<K, V, Hash, KeyEq, StlAllocator<Pair<const K, V>>>;
187
193 template <typename K, typename Hash = std::hash<K>, typename KeyEq = std::equal_to<K>>
194 using HashSet = std::unordered_set<K, Hash, KeyEq, StlAllocator<K>>;
195
203 template <typename K, typename V, typename Predicate = std::less<K>>
204 using MultiMap = std::multimap<K, V, Predicate, StlAllocator<Pair<const K, V>>>;
212 template <typename T>
213 using Deque = std::deque<T, StlAllocator<T>>;
221 template <typename T>
222 using Stack = std::stack<T, Deque<T>>;
230 template <typename T>
231 using List = std::list<T, StlAllocator<T>>;
239 template <typename T, typename Container = Deque<T>>
240 using Queue = std::queue<T, Container>;
248 template <typename T, typename Predicate = std::less<T>, typename Container = Vector<T>>
249 using PriorityQueue = std::priority_queue<T, Container, Predicate>;
250
254 template <typename T>
255 struct Optional : public std::optional<T>
256 {
257 using Base = std::optional<T>;
258
259 using Base::Base;
260
261 Optional() = default;
262 Optional(const Optional&) = default;
263 Optional(Optional&&) = default;
264
265 Optional& operator=(const Optional&) = default;
267
268 Optional& operator=(std::nullopt_t) noexcept
269 {
270 Base::operator=(std::nullopt);
271 return *this;
272 }
273
274 Optional& operator=(const T& value)
275 {
276 Base::operator=(value);
277 return *this;
278 }
279
280 Optional& operator=(T&& value)
281 {
282 Base::operator=(std::move(value));
283 return *this;
284 }
285
286 T& Get()
287 {
288 T* ptr = GetIf();
289 CHECK_MSG(ptr, "null-optional access");
290 return *ptr;
291 }
292
293 const T& Get() const
294 {
295 const T* ptr = GetIf();
296 CHECK_MSG(ptr, "null-optional access");
297 return *ptr;
298 }
299
300 T* GetIf() { return Base::has_value() ? std::addressof(Base::value()) : nullptr; }
301
302 const T* GetIf() const { return Base::has_value() ? std::addressof(Base::value()) : nullptr; }
303 };
305 template <typename... T>
306 struct Visitor : T...
307 {
308 using T::operator()...;
309 };
310 template <typename... T>
311 struct VisitorDefault : T...
312 {
313 using T::operator()...;
314 template <typename Arg>
315 requires(!std::is_invocable_v<T, Arg&> && ...)
316 auto operator()(Arg&) { /* nop */ };
317 };
323 template <typename... Args>
324 struct Variant : public std::variant<Args...>
325 {
326 using Base = std::variant<Args...>;
327
328 using Base::Base;
329 using Base::operator=;
330
331 private:
332 template <typename R, std::size_t I = 0, typename Vis, typename Var>
333 static R VisitImpl(Vis& vis, Var& var) noexcept
334 {
335 if constexpr (I >= sizeof...(Args))
336 {
337 CHECK_MSG(false, "valueless variant access");
338 std::terminate();
339 }
340 else
341 {
342 if (var.index() == I)
343 {
344 auto* p = std::get_if<I>(&var);
345 CHECK_MSG(p, "variant index/get_if mismatch");
346
347 if constexpr (std::is_void_v<R>)
348 {
349 std::invoke(vis, *p);
350 return;
351 }
352 else
353 {
354 return std::invoke(vis, *p);
355 }
356 }
357
358 return VisitImpl<R, I + 1>(vis, var);
359 }
360 }
361
362 public:
363 template <typename... Visitors>
364 auto Visit(Visitors&&... visitors) noexcept
365 {
366 using Vis = Visitor<std::decay_t<Visitors>...>;
367
368 static_assert((std::is_invocable_v<Vis&, Args&> && ...), "Visitor must handle every variant alternative");
369
370 using R = std::invoke_result_t<Vis&, std::variant_alternative_t<0, Base>&>;
371
372 static_assert((std::same_as<R, std::invoke_result_t<Vis&, Args&>> && ...),
373 "All visitor overloads must return the same type");
374
375 Vis vis{std::forward<Visitors>(visitors)...};
376 Base& base = *this;
377
378 return VisitImpl<R>(vis, base);
379 }
380
381 template <typename... Visitors>
382 auto Visit(Visitors&&... visitors) const noexcept
383 {
384 using Vis = Visitor<std::decay_t<Visitors>...>;
385 using ConstBase = const Base;
386
387 static_assert((std::is_invocable_v<Vis&, const Args&> && ...),
388 "Visitor must handle every variant alternative");
389
390
391 using R = std::invoke_result_t<Vis&, std::variant_alternative_t<0, ConstBase>&>;
392
393 static_assert((std::same_as<R, std::invoke_result_t<Vis&, const Args&>> && ...),
394 "All visitor overloads must return the same type");
395
396 Vis vis{std::forward<Visitors>(visitors)...};
397 const Base& base = *this;
398
399 return VisitImpl<R>(vis, base);
400 }
401
402 template <typename... Visitors>
403 auto VisitDefault(Visitors&&... visitors) noexcept
404 {
405 using Vis = VisitorDefault<std::decay_t<Visitors>...>;
406
407 static_assert((std::is_invocable_v<Vis&, Args&> && ...), "Visitor must handle every variant alternative");
408
409 using R = std::invoke_result_t<Vis&, std::variant_alternative_t<0, Base>&>;
410
411 static_assert((std::same_as<R, std::invoke_result_t<Vis&, Args&>> && ...),
412 "All visitor overloads must return the same type");
413
414 Vis vis{std::forward<Visitors>(visitors)...};
415 Base& base = *this;
416
417 return VisitImpl<R>(vis, base);
418 }
419
420 template <typename... Visitors>
421 auto VisitDefault(Visitors&&... visitors) const noexcept
422 {
423 using Vis = VisitorDefault<std::decay_t<Visitors>...>;
424 using ConstBase = const Base;
425
426 static_assert((std::is_invocable_v<Vis&, const Args&> && ...),
427 "Visitor must handle every variant alternative");
428
429 static_assert((std::is_nothrow_invocable_v<Vis&, const Args&> && ...),
430 "Visitor must be noexcept for every variant alternative");
431
432 using R = std::invoke_result_t<Vis&, std::variant_alternative_t<0, ConstBase>&>;
433
434 static_assert((std::same_as<R, std::invoke_result_t<Vis&, const Args&>> && ...),
435 "All visitor overloads must return the same type");
436
437 Vis vis{std::forward<Visitors>(visitors)...};
438 const Base& base = *this;
439
440 return VisitImpl<R>(vis, base);
441 }
442 // std::get<T>
443 template <typename T>
444 constexpr T& Get()
445 {
446 CHECK_MSG(GetIf<T>(), "null-variant access");
447 return *GetIf<T>();
448 }
449
450
451 // std::get<T>
452 template <typename T>
453 [[nodiscard]] constexpr const T& Get() const
454 {
455 CHECK_MSG(GetIf<T>(), "null-variant access");
456 return *GetIf<T>();
457 }
458
459
460 // std::get_if<T>
461 template <typename T>
462 constexpr T* GetIf()
463 {
464 return std::get_if<T>(this);
465 }
466
467
468 // std::get_if<T>
469 template <typename T>
470 [[nodiscard]] constexpr const T* GetIf() const
471 {
472 return std::get_if<T>(this);
473 }
474 };
478 namespace Ranges
479 {
480 using namespace std::ranges;
484 template <typename Range>
486 {
487 Range const& range;
488 ContainedBy(Range const& range) : range(range) {}
489 constexpr bool operator()(auto&& value) const
490 {
491 return std::ranges::find(range, value) != std::ranges::end(range);
492 }
493 };
497 template <typename T>
498 constexpr Optional<range_value_t<T>> FirstOf(T&& range)
499 {
500 if (auto it = std::ranges::begin(range); it != std::ranges::end(range))
501 return *it;
502 return {};
503 }
504 } // namespace Ranges
508 template <typename T>
509 [[nodiscard]] constexpr uint64_t FNV1a64(Span<const T> span) noexcept
510 {
511 return FNV1a64CombineBytes(kFNV1a64OffsetBasis, span.data(), span.size_bytes());
512 }
513 template <typename T>
514 [[nodiscard]] constexpr uint64_t FNV1a64(Span<T> span) noexcept
515 {
516 return FNV1a64CombineBytes(kFNV1a64OffsetBasis, span.data(), span.size_bytes());
517 }
518} // namespace Foundation::Core
#define CHECK_MSG(expr, format_str,...)
Allocator interface (noexcept)
Definition Allocator.hpp:29
virtual void Deallocate(pointer ptr) noexcept=0
virtual pointer Allocate(size_type size, size_t alignment=alignof(std::max_align_t)) noexcept=0
constexpr Optional< range_value_t< T > > FirstOf(T &&range)
Returns the first element of a range, or an empty Optional if the range is empty.
Definition Container.hpp:498
Lock-free atomic primitives and implementations of data structures.
Definition Allocator.hpp:6
std::vector< T, StlAllocator< T > > Vector
std::vector with explicit Foundation::Core::StlAllocator constructor
Definition Container.hpp:149
std::tuple< Args... > Tuple
Alias for std::tuple
Definition Container.hpp:39
std::multimap< K, V, Predicate, StlAllocator< Pair< const K, V > > > MultiMap
std::multimap with explicit Foundation::Core::StlAllocator constructor
Definition Container.hpp:204
uint64_t FNV1a64CombineBytes(uint64_t hash, void const *data, size_t size) noexcept
Definition Hash.hpp:18
std::queue< T, Container > Queue
std::queue with explicit Foundation::Core::StlAllocator constructor
Definition Container.hpp:240
std::basic_string< char, std::char_traits< char >, StlAllocator< char > > StringAlloc
std::basic_string<char> with explicit Foundation::Core::StlAllocator constructor
Definition Container.hpp:139
void DestructSpan(Allocator *resource, Span< T > span)
Convenience function for destructing a Span allocated with ConstructSpan. Calls destructors in-place ...
Definition Container.hpp:101
Span< T > ConstructSpan(Allocator *resource, size_t size, Args &&... args)
Convenience function for constructing a Span with memory allocated from a Foundation::Core::Allocator...
Definition Container.hpp:86
std::pair< First, Second > Pair
Alias for std::pair
Definition Container.hpp:33
constexpr String Format(fmt::format_string< Args... > format, Args &&... args)
String wrapper for Format().
Definition Container.hpp:126
std::unordered_set< K, Hash, KeyEq, StlAllocator< K > > HashSet
std::unordered_set with explicit Foundation::Core::StlAllocator constructor.
Definition Container.hpp:194
constexpr uint64_t FNV1a64(Span< const T > span) noexcept
Definition Container.hpp:509
std::set< T, Predicate, StlAllocator< T > > Set
std::set with explicit Foundation::Core::StlAllocator constructor
Definition Container.hpp:158
std::unordered_map< K, V, Hash, KeyEq, StlAllocator< Pair< const K, V > > > HashMap
std::unordered_map with explicit Foundation::Core::StlAllocator constructor.
Definition Container.hpp:186
std::map< K, V, Predicate, StlAllocator< Pair< const K, V > > > Map
std::map with explicit Foundation::Core::StlAllocator constructor
Definition Container.hpp:178
std::list< T, StlAllocator< T > > List
std::list with explicit Foundation::Core::StlAllocator constructor
Definition Container.hpp:231
std::bitset< Size > Bitset
Alias for std::bitset
Definition Container.hpp:51
Span< const T > AsSpan(T const &data)
Helper to construct one const r-value as a single element span.
Definition Container.hpp:73
std::basic_string< char, std::char_traits< char >, StlDefaultAllocator< char > > String
Alias for std::basic_string<char>, without an explicit allocator constructor.
Definition Container.hpp:120
std::priority_queue< T, Container, Predicate > PriorityQueue
std::priority_queue with explicit Foundation::Core::StlAllocator constructor
Definition Container.hpp:249
constexpr uint64_t kFNV1a64OffsetBasis
Definition Hash.hpp:10
std::stack< T, Deque< T > > Stack
std::stack with explicit Foundation::Core::StlAllocator constructor
Definition Container.hpp:222
std::multiset< T, Predicate, StlAllocator< T > > MultiSet
std::multiset with explicit Foundation::Core::StlAllocator constructor
Definition Container.hpp:168
std::array< T, Size > Array
Alias for std::array
Definition Container.hpp:45
std::basic_string_view< char > StringView
Alias for std::basic_string_view<char>
Definition Container.hpp:56
Span< const char > AsBytes(Span< T > data)
Definition Container.hpp:65
std::span< T > Span
Alias for std::span
Definition Container.hpp:62
std::deque< T, StlAllocator< T > > Deque
std::deque with explicit Foundation::Core::StlAllocator constructor
Definition Container.hpp:213
std::optional with convenience Get()/GetIf() methods.
Definition Container.hpp:256
const T & Get() const
Definition Container.hpp:293
T * GetIf()
Definition Container.hpp:300
Optional & operator=(Optional &&)=default
Optional & operator=(const T &value)
Definition Container.hpp:274
std::optional< T > Base
Definition Container.hpp:257
Optional(Optional &&)=default
const T * GetIf() const
Definition Container.hpp:302
Optional & operator=(const Optional &)=default
Optional(const Optional &)=default
Optional & operator=(T &&value)
Definition Container.hpp:280
Optional & operator=(std::nullopt_t) noexcept
Definition Container.hpp:268
T & Get()
Definition Container.hpp:286
Range predicate that checks if a value is contained within a given range.
Definition Container.hpp:486
constexpr bool operator()(auto &&value) const
Definition Container.hpp:489
ContainedBy(Range const &range)
Definition Container.hpp:488
Range const & range
Definition Container.hpp:487
std::allocator adaptor for Foundation::Core::Allocator
Definition Allocator.hpp:87
Definition Allocator.hpp:246
std::variant with C++23 visit() behavior and convenience Get()/GetIf() methods. Also read upon https:...
Definition Container.hpp:325
constexpr T * GetIf()
Definition Container.hpp:462
auto Visit(Visitors &&... visitors) const noexcept
Definition Container.hpp:382
auto VisitDefault(Visitors &&... visitors) const noexcept
Definition Container.hpp:421
auto Visit(Visitors &&... visitors) noexcept
Definition Container.hpp:364
std::variant< Args... > Base
Definition Container.hpp:326
constexpr const T & Get() const
Definition Container.hpp:453
constexpr const T * GetIf() const
Definition Container.hpp:470
auto VisitDefault(Visitors &&... visitors) noexcept
Definition Container.hpp:403
static R VisitImpl(Vis &vis, Var &var) noexcept
Definition Container.hpp:333
constexpr T & Get()
Definition Container.hpp:444