KTL
segragator.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 "segragator_fwd.h"
6 #include "type_allocator.h"
7 
8 #include <memory>
9 #include <type_traits>
10 
11 namespace ktl
12 {
19  template<size_t Threshold, typename P, typename F>
20  class segragator
21  {
22  private:
23  static_assert(detail::has_no_value_type_v<P>, "Building on top of typed allocators is not allowed. Use allocators without a type");
24  static_assert(detail::has_no_value_type_v<F>, "Building on top of typed allocators is not allowed. Use allocators without a type");
25 
26  public:
28 
29  segragator() = default;
30 
34  template<typename Primary,
35  typename = std::enable_if_t<std::is_constructible_v<P, Primary>>>
36  explicit segragator(Primary&& primary)
37  noexcept(std::is_nothrow_constructible_v<P, Primary> && std::is_nothrow_default_constructible_v<F>) :
38  m_Primary(std::forward<Primary>(primary)),
39  m_Fallback() {}
40 
44  template<typename Primary, typename Fallback,
45  typename = std::enable_if_t<
46  std::is_constructible_v<P, Primary> &&
47  std::is_constructible_v<F, Fallback>>>
48  explicit segragator(Primary&& primary, Fallback&& fallback)
49  noexcept(std::is_nothrow_constructible_v<P, Primary> && std::is_nothrow_constructible_v<F, Fallback>) :
50  m_Primary(std::forward<Primary>(primary)),
51  m_Fallback(std::forward<Fallback>(fallback)) {}
52 
56  template<typename... Args,
57  typename = std::enable_if_t<
58  std::is_constructible_v<P, Args...>>>
59  explicit segragator(std::tuple<Args...>&& primary)
60  noexcept(std::is_nothrow_constructible_v<P, Args...> && std::is_nothrow_default_constructible_v<F>) :
61  m_Primary(std::make_from_tuple<P>(std::forward<std::tuple<Args...>>(primary))),
62  m_Fallback() {}
63 
67  template<typename... ArgsP, typename... ArgsF,
68  typename = std::enable_if_t<
69  std::is_constructible_v<P, ArgsP...> &&
70  std::is_constructible_v<F, ArgsF...>>>
71  explicit segragator(std::tuple<ArgsP...>&& primary, std::tuple<ArgsF...>&& fallback)
72  noexcept(std::is_nothrow_constructible_v<P, ArgsP...> && std::is_nothrow_constructible_v<F, ArgsF...>) :
73  m_Primary(std::make_from_tuple<P>(std::forward<std::tuple<ArgsP...>>(primary))),
74  m_Fallback(std::make_from_tuple<F>(std::forward<std::tuple<ArgsF...>>(fallback))) {}
75 
76  segragator(const segragator&) = default;
77 
78  segragator(segragator&&) = default;
79 
80  segragator& operator=(const segragator&) = default;
81 
83 
84  bool operator==(const segragator& rhs) const
85  noexcept(detail::has_nothrow_equal_v<P> && detail::has_nothrow_equal_v<F>)
86  {
87  return m_Primary == rhs.m_Primary && m_Fallback == rhs.m_Fallback;
88  }
89 
90  bool operator!=(const segragator& rhs) const
91  noexcept(detail::has_nothrow_not_equal_v<P>&& detail::has_nothrow_not_equal_v<F>)
92  {
93  return m_Primary != rhs.m_Primary || m_Fallback != rhs.m_Fallback;
94  }
95 
96 #pragma region Allocation
97  void* allocate(size_t n)
98  noexcept(detail::has_nothrow_allocate_v<P> && detail::has_nothrow_allocate_v<F>)
99  {
100  if (n <= Threshold)
101  return m_Primary.allocate(n);
102  else
103  return m_Fallback.allocate(n);
104  }
105 
106  void deallocate(void* p, size_t n)
107  noexcept(detail::has_nothrow_deallocate_v<P> && detail::has_nothrow_deallocate_v<F>)
108  {
109  if (n <= Threshold)
110  return m_Primary.deallocate(p, n);
111  else
112  return m_Fallback.deallocate(p, n);
113  }
114 #pragma endregion
115 
116 #pragma region Construction
117  template<typename T, typename... Args>
118  typename std::enable_if<detail::has_construct_v<P, T*, Args...> || detail::has_construct_v<F, T*, Args...>, void>::type
119  construct(T* p, Args&&... args) noexcept(
120  (!detail::has_construct_v<P, T*, Args...> || detail::has_nothrow_construct_v<P, T*, Args...>) &&
121  (!detail::has_construct_v<F, T*, Args...> || detail::has_nothrow_construct_v<F, T*, Args...>) &&
122  std::is_nothrow_constructible_v<T, Args...>)
123  {
124  bool owned = m_Primary.owns(p);
125 
126  if constexpr (detail::has_construct_v<P, T*, Args...>)
127  {
128  if (owned)
129  {
130  m_Primary.construct(p, std::forward<Args>(args)...);
131  return;
132  }
133  }
134 
135  if constexpr (detail::has_construct_v<F, T*, Args...>)
136  {
137  if (!owned)
138  {
139  m_Fallback.construct(p, std::forward<Args>(args)...);
140  return;
141  }
142  }
143 
144  ::new(p) T(std::forward<Args>(args)...);
145  }
146 
147  template<typename T>
148  typename std::enable_if<detail::has_destroy_v<P, T*> || detail::has_destroy_v<F, T*>, void>::type
149  destroy(T* p) noexcept(
150  (!detail::has_destroy_v<P, T*> || detail::has_nothrow_destroy_v<P, T*>) &&
151  (!detail::has_destroy_v<F, T*> || detail::has_nothrow_destroy_v<F, T*>) &&
152  std::is_nothrow_destructible_v<T>)
153  {
154  bool owned = m_Primary.owns(p);
155 
156  if constexpr (detail::has_destroy_v<P, T*>)
157  {
158  if (owned)
159  {
160  m_Primary.destroy(p);
161  return;
162  }
163  }
164 
165  if constexpr (detail::has_destroy_v<F, T*>)
166  {
167  if (!owned)
168  {
169  m_Fallback.destroy(p);
170  return;
171  }
172  }
173 
174  p->~T();
175  }
176 #pragma endregion
177 
178 #pragma region Utility
179  template<typename Primary = P, typename Fallback = F>
180  typename std::enable_if<detail::has_max_size_v<Primary> && detail::has_max_size_v<Fallback>, size_type>::type
181  max_size() const
182  noexcept(detail::has_nothrow_max_size_v<Primary> && detail::has_nothrow_max_size_v<Fallback>)
183  {
184  return (std::max)(m_Primary.max_size(), m_Fallback.max_size());
185  }
186 
187  template<typename Primary = P, typename Fallback = F>
188  typename std::enable_if<detail::has_owns_v<Primary> && detail::has_owns_v<Fallback>, bool>::type
189  owns(void* p) const
190  noexcept(detail::has_nothrow_owns_v<Primary> && detail::has_nothrow_owns_v<Fallback>)
191  {
192  if (m_Primary.owns(p))
193  return true;
194 
195  return m_Fallback.owns(p);
196  }
197 #pragma endregion
198 
199  private:
200  KTL_EMPTY_BASE P m_Primary;
201  KTL_EMPTY_BASE F m_Fallback;
202  };
203 }
An allocator which delegates allocations between 2 different allocators. It first attempts to allocat...
Definition: fallback.h:23
An allocator which delegates allocations between 2 different allocators based on a size threshold.
Definition: segragator.h:21
segragator(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: segragator.h:48
void * allocate(size_t n) noexcept(detail::has_nothrow_allocate_v< P > &&detail::has_nothrow_allocate_v< F >)
Definition: segragator.h:97
bool operator!=(const segragator &rhs) const noexcept(detail::has_nothrow_not_equal_v< P > &&detail::has_nothrow_not_equal_v< F >)
Definition: segragator.h:90
segragator(segragator &&)=default
detail::get_size_type_t< P > size_type
Definition: segragator.h:23
segragator(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: segragator.h:59
segragator(const segragator &)=default
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: segragator.h:149
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: segragator.h:189
segragator & operator=(segragator &&)=default
segragator()=default
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: segragator.h:181
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: segragator.h:119
bool operator==(const segragator &rhs) const noexcept(detail::has_nothrow_equal_v< P > &&detail::has_nothrow_equal_v< F >)
Definition: segragator.h:84
segragator(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: segragator.h:71
segragator & operator=(const segragator &)=default
segragator(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: segragator.h:36
void deallocate(void *p, size_t n) noexcept(detail::has_nothrow_deallocate_v< P > &&detail::has_nothrow_deallocate_v< F >)
Definition: segragator.h:106
#define KTL_EMPTY_BASE
Definition: empty_base.h:6
constexpr bool has_construct_v
Definition: meta.h:41
typename get_size_type< Alloc, void >::type get_size_type_t
Definition: meta.h:31
constexpr bool has_nothrow_max_size_v
Definition: meta.h:122
Definition: cascading.h:15