KTL
type_allocator.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "../utility/empty_base.h"
4 #include "../utility/meta.h"
5 
6 #include "type_allocator_fwd.h"
7 
8 #include <memory>
9 #include <type_traits>
10 
11 namespace ktl
12 {
18  template<typename T, typename Alloc>
20  {
21  private:
22  static_assert(detail::has_no_value_type_v<Alloc>, "Building on top of typed allocators is not allowed. Use allocators without a type");
23  static_assert(!std::is_const_v<T>, "Using an allocator of const T is ill-formed");
24  static_assert(!std::is_copy_constructible_v<Alloc> || std::is_nothrow_copy_constructible_v<Alloc>, "Using a throwing copy constructor is ill-formed");
25  static_assert(!std::is_move_constructible_v<Alloc> || std::is_nothrow_move_constructible_v<Alloc>, "Using a throwing move constructor is ill-formed");
26  static_assert(!std::is_copy_assignable_v<Alloc> || std::is_nothrow_copy_assignable_v<Alloc>, "Using throwing copy assignment is ill-formed");
27  static_assert(!std::is_move_assignable_v<Alloc> || std::is_nothrow_move_assignable_v<Alloc>, "Using throwing move assignment is ill-formed");
28 
29  template<typename U, typename A>
30  friend class type_allocator;
31 
32  public:
33  typedef T value_type;
35  typedef std::false_type is_always_equal;
36 
37  template<typename U>
38  struct rebind
39  {
41  };
42 
47  type_allocator() = default;
48 
52  template<typename... Args,
53  typename = std::enable_if_t<
54  std::is_constructible_v<Alloc, Args...>>>
55  explicit type_allocator(Args&&... alloc)
56  noexcept(std::is_nothrow_constructible_v<T, Args...>) :
57  m_Alloc(std::forward<Args>(alloc)...) {}
58 
59  type_allocator(const type_allocator&) = default;
60 
61  // Move construction is essentially forbidden for STL allocators
62  // A al(std::move(a)); a == al
63  // https://en.cppreference.com/w/cpp/named_req/Allocator
65  noexcept(std::is_nothrow_copy_constructible_v<Alloc>) :
66  m_Alloc(other.m_Alloc) {}
67 
68  template<typename U>
70  noexcept(std::is_nothrow_constructible_v<Alloc, const type_allocator<U, Alloc>&>) :
71  m_Alloc(other.m_Alloc) {}
72 
73  // Move construction is essentially forbidden for STL allocators
74  // https://en.cppreference.com/w/cpp/named_req/Allocator
75  template<typename U>
77  noexcept(std::is_nothrow_constructible_v<Alloc, type_allocator<U, Alloc>&&>) :
78  m_Alloc(other.m_Alloc) {}
79 
81 
82  // Move construction is essentially forbidden for STL allocators
83  // https://en.cppreference.com/w/cpp/named_req/Allocator
85  noexcept(std::is_nothrow_copy_assignable_v<Alloc>)
86  {
87  m_Alloc = rhs.m_Alloc;
88 
89  return *this;
90  }
91 
92 #pragma region Allocation
98  value_type* allocate(size_t n)
99  noexcept(noexcept(m_Alloc.allocate(n)))
100  {
101  return reinterpret_cast<value_type*>(m_Alloc.allocate(sizeof(value_type) * n));
102  }
103 
109  void deallocate(value_type* p, size_t n)
110  noexcept(noexcept(m_Alloc.deallocate(p, n)))
111  {
112  m_Alloc.deallocate(p, sizeof(value_type) * n);
113  }
114 #pragma endregion
115 
116 #pragma region Construction
124  template<typename... Args>
125  typename std::enable_if<detail::has_construct_v<Alloc, value_type*, Args...>, void>::type
126  construct(value_type* p, Args&&... args)
127  noexcept(detail::has_nothrow_construct_v<Alloc, value_type*, Args...>)
128  {
129  m_Alloc.construct(p, std::forward<Args>(args)...);
130  }
131 
137  template<typename A = Alloc>
138  typename std::enable_if<detail::has_destroy_v<A, value_type*>, void>::type
140  noexcept(detail::has_nothrow_destroy_v<Alloc, value_type*>)
141  {
142  m_Alloc.destroy(p);
143  }
144 #pragma endregion
145 
146 #pragma region Utility
152  template<typename A = Alloc>
153  typename std::enable_if<detail::has_max_size_v<A>, size_type>::type
154  max_size() const
155  noexcept(detail::has_nothrow_max_size_v<A>)
156  {
157  return m_Alloc.max_size() / sizeof(T);
158  }
159 
166  template<typename A = Alloc>
167  typename std::enable_if<detail::has_owns_v<A>, bool>::type
168  owns(value_type* p) const
169  noexcept(detail::has_nothrow_owns_v<A>)
170  {
171  return m_Alloc.owns(p);
172  }
173 #pragma endregion
174 
179  Alloc& get_allocator() noexcept
180  {
181  return m_Alloc;
182  }
183 
188  const Alloc& get_allocator() const noexcept
189  {
190  return m_Alloc;
191  }
192 
193  private:
194  KTL_EMPTY_BASE Alloc m_Alloc;
195  };
196 
197  template<typename T, typename U, typename Alloc>
199  noexcept(detail::has_nothrow_equal_v<Alloc>)
200  {
201  return lhs.get_allocator() == rhs.get_allocator();
202  }
203 
204  template<typename T, typename U, typename Alloc>
206  noexcept(detail::has_nothrow_not_equal_v<Alloc>)
207  {
208  return lhs.get_allocator() != rhs.get_allocator();
209  }
210 }
Wrapper class for making an untyped allocator into a typed allocator.
Definition: type_allocator.h:20
type_allocator(type_allocator &&other) noexcept(std::is_nothrow_copy_constructible_v< Alloc >)
Definition: type_allocator.h:64
type_allocator & operator=(const type_allocator &)=default
detail::get_size_type_t< Alloc > size_type
Definition: type_allocator.h:34
type_allocator(type_allocator< U, Alloc > &&other) noexcept(std::is_nothrow_constructible_v< Alloc, type_allocator< U, Alloc > && >)
Definition: type_allocator.h:76
type_allocator & operator=(type_allocator &&rhs) noexcept(std::is_nothrow_copy_assignable_v< Alloc >)
Definition: type_allocator.h:84
std::false_type is_always_equal
Definition: type_allocator.h:35
std::enable_if< detail::has_construct_v< Alloc, value_type *, Args... >, void >::type construct(value_type *p, Args &&... args) noexcept(detail::has_nothrow_construct_v< Alloc, value_type *, Args... >)
Constructs an object of T with the given ...args at the given location.
Definition: type_allocator.h:126
std::enable_if< detail::has_max_size_v< A >, size_type >::type max_size() const noexcept(detail::has_nothrow_max_size_v< A >)
Returns the maximum size that an allocation of objects can be.
Definition: type_allocator.h:154
value_type * allocate(size_t n) noexcept(noexcept(m_Alloc.allocate(n)))
Attempts to allocate a chunk of memory defined by n.
Definition: type_allocator.h:98
std::enable_if< detail::has_owns_v< A >, bool >::type owns(value_type *p) const noexcept(detail::has_nothrow_owns_v< A >)
Returns whether or not the allocator owns the given location in memory.
Definition: type_allocator.h:168
type_allocator()=default
Default constructor.
Alloc & get_allocator() noexcept
Returns a reference to the underlying allocator.
Definition: type_allocator.h:179
std::enable_if< detail::has_destroy_v< A, value_type * >, void >::type destroy(value_type *p) noexcept(detail::has_nothrow_destroy_v< Alloc, value_type * >)
Destructs an object of T at the given location.
Definition: type_allocator.h:139
void deallocate(value_type *p, size_t n) noexcept(noexcept(m_Alloc.deallocate(p, n)))
Attempts to deallocate the memory at location p.
Definition: type_allocator.h:109
type_allocator(const type_allocator< U, Alloc > &other) noexcept(std::is_nothrow_constructible_v< Alloc, const type_allocator< U, Alloc > & >)
Definition: type_allocator.h:69
type_allocator(const type_allocator &)=default
const Alloc & get_allocator() const noexcept
Returns a const reference to the underlying allocator.
Definition: type_allocator.h:188
T value_type
Definition: type_allocator.h:33
type_allocator(Args &&... alloc) noexcept(std::is_nothrow_constructible_v< T, Args... >)
Constructor for forwarding any arguments to the underlying allocator.
Definition: type_allocator.h:55
#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
bool operator!=(const type_allocator< T, Alloc > &lhs, const type_allocator< U, Alloc > &rhs) noexcept(detail::has_nothrow_not_equal_v< Alloc >)
Definition: type_allocator.h:205
bool operator==(const type_allocator< T, Alloc > &lhs, const type_allocator< U, Alloc > &rhs) noexcept(detail::has_nothrow_equal_v< Alloc >)
Definition: type_allocator.h:198
Definition: type_allocator.h:39
type_allocator< U, Alloc > other
Definition: type_allocator.h:40