KTL
Loading...
Searching...
No Matches
fallback.h
Go to the documentation of this file.
1#pragma once
2
3#include "../utility/empty_base.h"
4#include "../utility/meta.h"
5#include "../utility/source_location.h"
6#include "fallback_fwd.h"
7#include "type_allocator.h"
8
9#include <limits>
10#include <memory>
11#include <type_traits>
12
13namespace ktl
14{
22 template<typename P, typename F>
24 {
25 private:
26 static_assert(detail::has_no_value_type_v<P>, "Building on top of typed allocators is not allowed. Use allocators without a type");
27 static_assert(detail::has_no_value_type_v<F>, "Building on top of typed allocators is not allowed. Use allocators without a type");
28 static_assert(detail::has_owns_v<P>, "The primary allocator is required to have an 'owns(void*)' method");
29
30 public:
32
33 fallback() = default;
34
38 template<typename Primary,
39 typename = std::enable_if_t<std::is_constructible_v<P, Primary>>>
40 explicit fallback(Primary&& primary)
41 noexcept(std::is_nothrow_constructible_v<P, Primary> && std::is_nothrow_default_constructible_v<F>) :
42 m_Primary(std::forward<Primary>(primary)),
43 m_Fallback() {}
44
48 template<typename Primary, typename Fallback,
49 typename = std::enable_if_t<
50 std::is_constructible_v<P, Primary> &&
51 std::is_constructible_v<F, Fallback>>>
52 explicit fallback(Primary&& primary, Fallback&& fallback)
53 noexcept(std::is_nothrow_constructible_v<P, Primary> && std::is_nothrow_constructible_v<F, Fallback>) :
54 m_Primary(std::forward<Primary>(primary)),
55 m_Fallback(std::forward<Fallback>(fallback)) {}
56
60 template<typename... Args,
61 typename = std::enable_if_t<
62 std::is_constructible_v<P, Args...>>>
63 explicit fallback(std::tuple<Args...>&& primary)
64 noexcept(std::is_nothrow_constructible_v<P, Args...> && std::is_nothrow_default_constructible_v<F>) :
65 m_Primary(std::make_from_tuple<P>(std::forward<std::tuple<Args...>>(primary))),
66 m_Fallback() {}
67
71 template<typename... ArgsP, typename... ArgsF,
72 typename = std::enable_if_t<
73 std::is_constructible_v<P, ArgsP...>&&
74 std::is_constructible_v<F, ArgsF...>>>
75 explicit fallback(std::tuple<ArgsP...>&& primary, std::tuple<ArgsF...>&& fallback)
76 noexcept(std::is_nothrow_constructible_v<P, ArgsP...> && std::is_nothrow_constructible_v<F, ArgsF...>) :
77 m_Primary(std::make_from_tuple<P>(std::forward<std::tuple<ArgsP...>>(primary))),
78 m_Fallback(std::make_from_tuple<F>(std::forward<std::tuple<ArgsF...>>(fallback))) {}
79
80 fallback(const fallback&) = default;
81
82 fallback(fallback&&) = default;
83
84 fallback& operator=(const fallback&) = default;
85
87
88 bool operator==(const fallback& rhs) const
90 {
91 return m_Primary == rhs.m_Primary && m_Fallback == rhs.m_Fallback;
92 }
93
94 bool operator!=(const fallback& rhs) const
96 {
97 return m_Primary != rhs.m_Primary || m_Fallback != rhs.m_Fallback;
98 }
99
100#pragma region Allocation
101 void* allocate(size_t n, const source_location source = KTL_SOURCE())
102 noexcept(detail::has_nothrow_allocate_v<P> && detail::has_nothrow_allocate_v<F>)
103 {
104 void* ptr = detail::allocate(m_Primary, n, source);
105 if (!ptr)
106 return detail::allocate(m_Fallback, n, source);
107 return ptr;
108 }
109
110 void deallocate(void* p, size_t n)
112 {
113 if (m_Primary.owns(p))
114 {
115 m_Primary.deallocate(p, n);
116 return;
117 }
118
119 m_Fallback.deallocate(p, n);
120 }
121#pragma endregion
122
123#pragma region Construction
124 template<typename T, typename... Args>
125 typename std::enable_if<detail::has_construct_v<P, T*, Args...> || detail::has_construct_v<F, T*, Args...>, void>::type
126 construct(T* p, Args&&... args) noexcept(
127 (!detail::has_construct_v<P, T*, Args...> || detail::has_nothrow_construct_v<P, T*, Args...>) &&
129 std::is_nothrow_constructible_v<T, Args...>)
130 {
131 bool owned = m_Primary.owns(p);
132
133 if constexpr (detail::has_construct_v<P, T*, Args...>)
134 {
135 if (owned)
136 {
137 m_Primary.construct(p, std::forward<Args>(args)...);
138 return;
139 }
140 }
141
142 if constexpr (detail::has_construct_v<F, T*, Args...>)
143 {
144 if (!owned)
145 {
146 m_Fallback.construct(p, std::forward<Args>(args)...);
147 return;
148 }
149 }
150
151 ::new(p) T(std::forward<Args>(args)...);
152 }
153
154 template<typename T>
155 typename std::enable_if<detail::has_destroy_v<P, T*> || detail::has_destroy_v<F, T*>, void>::type
156 destroy(T* p) noexcept(
159 std::is_nothrow_destructible_v<T>)
160 {
161 bool owned = m_Primary.owns(p);
162
163 if constexpr (detail::has_destroy_v<P, T*>)
164 {
165 if (owned)
166 {
167 m_Primary.destroy(p);
168 return;
169 }
170 }
171
172 if constexpr (detail::has_destroy_v<F, T*>)
173 {
174 if (!owned)
175 {
176 m_Fallback.destroy(p);
177 return;
178 }
179 }
180
181 p->~T();
182 }
183#pragma endregion
184
185#pragma region Utility
186 template<typename Primary = P, typename Fallback = F>
187 typename std::enable_if<detail::has_max_size_v<Primary> && detail::has_max_size_v<Fallback>, size_type>::type
188 max_size() const
189 noexcept(detail::has_nothrow_max_size_v<Primary> && detail::has_nothrow_max_size_v<Fallback>)
190 {
191 return (std::max)(m_Primary.max_size(), m_Fallback.max_size());
192 }
193
194 template<typename Primary = P, typename Fallback = F>
195 typename std::enable_if<detail::has_owns_v<Primary> && detail::has_owns_v<Fallback>, bool>::type
196 owns(void* p) const
198 {
199 if (m_Primary.owns(p))
200 return true;
201
202 return m_Fallback.owns(p);
203 }
204#pragma endregion
205
206 private:
207 KTL_EMPTY_BASE P m_Primary;
208 KTL_EMPTY_BASE F m_Fallback;
209 };
210}
An allocator which delegates allocations between 2 different allocators. It first attempts to allocat...
Definition fallback.h:24
std::enable_if< detail::has_max_size_v< Primary > &&detail::has_max_size_v< Fallback >, size_type >::type max_size() const noexcept(detail::has_nothrow_max_size_v< Primary > &&detail::has_nothrow_max_size_v< Fallback >)
Definition fallback.h:188
fallback(std::tuple< ArgsP... > &&primary, std::tuple< ArgsF... > &&fallback) noexcept(std::is_nothrow_constructible_v< P, ArgsP... > &&std::is_nothrow_constructible_v< F, ArgsF... >)
Constructor for forwarding a tuple of arguments to the primary and fallback allocators.
Definition fallback.h:75
fallback(fallback &&)=default
fallback & operator=(fallback &&)=default
fallback(std::tuple< Args... > &&primary) noexcept(std::is_nothrow_constructible_v< P, Args... > &&std::is_nothrow_default_constructible_v< F >)
Constructor for forwarding a tuple of arguments to the primary allocator.
Definition fallback.h:63
bool operator!=(const fallback &rhs) const noexcept(detail::has_nothrow_not_equal_v< P > &&detail::has_nothrow_not_equal_v< F >)
Definition fallback.h:94
fallback()=default
fallback(const fallback &)=default
fallback & operator=(const fallback &)=default
fallback(Primary &&primary, Fallback &&fallback) noexcept(std::is_nothrow_constructible_v< P, Primary > &&std::is_nothrow_constructible_v< F, Fallback >)
Constructor for forwarding a single argument to the primary and fallback allocators.
Definition fallback.h:52
bool operator==(const fallback &rhs) const noexcept(detail::has_nothrow_equal_v< P > &&detail::has_nothrow_equal_v< F >)
Definition fallback.h:88
std::enable_if< detail::has_construct_v< P, T *, Args... >||detail::has_construct_v< F, T *, Args... >, void >::type construct(T *p, Args &&... args) noexcept((!detail::has_construct_v< P, T *, Args... >||detail::has_nothrow_construct_v< P, T *, Args... >) &&(!detail::has_construct_v< F, T *, Args... >||detail::has_nothrow_construct_v< F, T *, Args... >) &&std::is_nothrow_constructible_v< T, Args... >)
Definition fallback.h:126
void * allocate(size_t n, const source_location source=KTL_SOURCE()) noexcept(detail::has_nothrow_allocate_v< P > &&detail::has_nothrow_allocate_v< F >)
Definition fallback.h:101
std::enable_if< detail::has_destroy_v< P, T * >||detail::has_destroy_v< F, T * >, void >::type destroy(T *p) noexcept((!detail::has_destroy_v< P, T * >||detail::has_nothrow_destroy_v< P, T * >) &&(!detail::has_destroy_v< F, T * >||detail::has_nothrow_destroy_v< F, T * >) &&std::is_nothrow_destructible_v< T >)
Definition fallback.h:156
void deallocate(void *p, size_t n) noexcept(detail::has_nothrow_deallocate_v< P > &&detail::has_nothrow_deallocate_v< F >)
Definition fallback.h:110
std::enable_if< detail::has_owns_v< Primary > &&detail::has_owns_v< Fallback >, bool >::type owns(void *p) const noexcept(detail::has_nothrow_owns_v< Primary > &&detail::has_nothrow_owns_v< Fallback >)
Definition fallback.h:196
detail::get_size_type_t< P > size_type
Definition fallback.h:31
fallback(Primary &&primary) noexcept(std::is_nothrow_constructible_v< P, Primary > &&std::is_nothrow_default_constructible_v< F >)
Constructor for forwarding a single argument to the primary allocator.
Definition fallback.h:40
#define KTL_EMPTY_BASE
Definition empty_base.h:6
typename get_size_type< Alloc, void >::type get_size_type_t
Definition meta.h:33
constexpr bool has_nothrow_construct_v
Definition meta.h:123
constexpr bool has_construct_v
Definition meta.h:53
void * allocate(Alloc &alloc, size_t n, const source_location source) noexcept(false)
Definition meta.h:161
constexpr bool has_no_value_type_v
Definition meta.h:17
Definition cascading.h:16
#define KTL_SOURCE()
Definition source_location.h:11
Definition source_location.h:19