bit::memory
Allocator.hpp
1 /*****************************************************************************
2  * \file
3  * \brief This header defines the concepts and type-traits relating to the
4  * Allocator concept
5  *****************************************************************************/
6 
7 /*
8  The MIT License (MIT)
9 
10  Copyright (c) 2018 Matthew Rodusek
11 
12  Permission is hereby granted, free of charge, to any person obtaining a copy
13  of this software and associated documentation files (the "Software"), to deal
14  in the Software without restriction, including without limitation the rights
15  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16  copies of the Software, and to permit persons to whom the Software is
17  furnished to do so, subject to the following conditions:
18 
19  The above copyright notice and this permission notice shall be included in
20  all copies or substantial portions of the Software.
21 
22  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28  SOFTWARE.
29 */
30 #ifndef BIT_MEMORY_CONCEPTS_ALLOCATOR_HPP
31 #define BIT_MEMORY_CONCEPTS_ALLOCATOR_HPP
32 
33 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
34 # pragma once
35 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
36 
37 #include "detail/identity.hpp" // detail::identity
38 #include "detail/void_t.hpp" // detail::void_t
39 #include "detail/allocator_utilities.hpp" // allocator_size_type
40 
41 #include "../utilities/allocator_info.hpp" // allocator_info
42 
43 #include <cstddef> // std::maxalign_t
44 #include <type_traits> // std::declval
45 
46 namespace bit {
47  namespace memory {
48 
188 #if __cplusplus >= 202000L
189  // TODO(bitwize) replace 202000L with the correct __cplusplus when certified
190  template<typename T>
191  concept Allocator = requires( T a,
192  allocator_pointer_t<T> p,
193  allocator_size_type_t<T> size,
194  allocator_size_type_t<T> align )
195  {
196  { a.try_allocate( size, align ) } -> allocator_pointer_t<T>;
197  { a.deallocate( p, size ) };
198  };
199 #endif
200 
201  namespace detail {
202 
203  //----------------------------------------------------------------------
204  // Allocator traits
205  //----------------------------------------------------------------------
206 
207  template<typename T, typename = void>
208  struct allocator_has_allocate_impl : std::false_type{};
209 
210  template<typename T>
211  struct allocator_has_allocate_impl<T,
212  void_t<decltype(std::declval<allocator_pointer_t<T>&>()
213  = std::declval<T&>().allocate( std::declval<allocator_size_type_t<T>>(),
214  std::declval<allocator_size_type_t<T>>() ))
215  >
216  > : std::true_type{};
217 
218  //----------------------------------------------------------------------
219 
220  template<typename T, typename = void>
221  struct allocator_has_allocate_hint_impl : std::false_type{};
222 
223  template<typename T>
224  struct allocator_has_allocate_hint_impl<T,
225  void_t<decltype(std::declval<allocator_pointer_t<T>&>()
226  = std::declval<T&>().allocate( std::declval<allocator_const_pointer_t<T>>(),
227  std::declval<allocator_size_type_t<T>>(),
228  std::declval<allocator_size_type_t<T>>() ))
229  >
230  > : std::true_type{};
231 
232  //----------------------------------------------------------------------
233 
234  template<typename T, typename = void>
235  struct allocator_has_try_allocate_impl : std::false_type{};
236 
237  template<typename T>
238  struct allocator_has_try_allocate_impl<T,
239  void_t<decltype(std::declval<allocator_pointer_t<T>&>()
240  = std::declval<T&>().try_allocate( std::declval<allocator_size_type_t<T>>(),
241  std::declval<allocator_size_type_t<T>>() ))
242  >
243  > : std::true_type{};
244 
245  //----------------------------------------------------------------------
246 
247  template<typename T, typename = void>
248  struct allocator_has_try_allocate_hint_impl : std::false_type{};
249 
250  template<typename T>
251  struct allocator_has_try_allocate_hint_impl<T,
252  void_t<decltype(std::declval<allocator_pointer_t<T>&>()
253  = std::declval<T&>().try_allocate( std::declval<allocator_const_pointer_t<T>>(),
254  std::declval<allocator_size_type_t<T>>(),
255  std::declval<allocator_size_type_t<T>>() ))
256  >
257  > : std::true_type{};
258 
259  //----------------------------------------------------------------------
260 
261  template<typename...> struct allocator_type_list;
262 
263  //----------------------------------------------------------------------
264 
265  template<typename T, typename U, typename List, typename = void>
266  struct allocator_has_construct_impl : std::false_type{};
267 
268  template<typename T, typename U, typename...Args>
269  struct allocator_has_construct_impl<T,U,allocator_type_list<Args...>,
270  void_t<
271  decltype( std::declval<T&>().template construct<U>( std::declval<void*>(), std::declval<Args>()... ) )
272  >
273  > : std::true_type{};
274 
275  //----------------------------------------------------------------------
276 
277  template<typename T, typename U, typename List, typename = void>
278  struct allocator_has_make_impl : std::false_type{};
279 
280  template<typename T, typename U, typename...Args>
281  struct allocator_has_make_impl<T,U,allocator_type_list<Args...>,
282  void_t<
283  decltype( std::declval<T&>().template make<U>( std::declval<Args>()... ) )
284  >
285  > : std::true_type{};
286 
287  //----------------------------------------------------------------------
288 
289  template<typename T, typename U, typename List, typename = void>
290  struct allocator_has_make_array_impl : std::false_type{};
291 
292  template<typename T, typename U, typename...Args>
293  struct allocator_has_make_array_impl<T,U,allocator_type_list<Args...>,
294  void_t<
295  decltype( std::declval<T&>().template make_array<U>( std::declval<Args>()... ) )
296  >
297  > : std::true_type{};
298 
299  //----------------------------------------------------------------------
300 
301  template<typename T, typename = void>
302  struct allocator_has_deallocate_impl : std::false_type{};
303 
304  template<typename T>
305  struct allocator_has_deallocate_impl<T,
306  void_t<decltype(std::declval<T&>().deallocate( std::declval<allocator_pointer_t<T>&>(),
307  std::declval<allocator_size_type_t<T>>() ))
308  >
309  > : std::true_type{};
310 
311  //----------------------------------------------------------------------
312 
313  template<typename T, typename = void>
314  struct allocator_has_deallocate_all_impl : std::false_type{};
315 
316  template<typename T>
317  struct allocator_has_deallocate_all_impl<T,
318  void_t<decltype(std::declval<T&>().deallocate_all())>
319  > : std::true_type{};
320 
321  //----------------------------------------------------------------------
322 
323  template<typename T, typename, typename = void>
324  struct allocator_has_destroy_impl : std::false_type{};
325 
326  template<typename T, typename U>
327  struct allocator_has_destroy_impl<T,U,
328  void_t<
329  decltype( std::declval<T&>().dispose( std::declval<U>() ) )
330  >
331  > : std::true_type{};
332 
333  //----------------------------------------------------------------------
334 
335  template<typename T, typename, typename = void>
336  struct allocator_has_dispose_impl : std::false_type{};
337 
338  template<typename T, typename U>
339  struct allocator_has_dispose_impl<T,U,
340  void_t<
341  decltype( std::declval<T&>().dispose( std::declval<U&>() ) )
342  >
343  > : std::true_type{};
344 
345  //----------------------------------------------------------------------
346 
347  template<typename T, typename, typename = void>
348  struct allocator_has_dispose_array_impl : std::false_type{};
349 
350  template<typename T, typename U>
351  struct allocator_has_dispose_array_impl<T,U,
352  void_t<
353  decltype( std::declval<T&>().dispose_array( std::declval<U&>(), std::declval<allocator_size_type_t<T>>() ) )
354  >
355  > : std::true_type{};
356 
357  //----------------------------------------------------------------------
358 
359  template<typename T, typename = void>
360  struct allocator_has_recommended_allocation_size_impl : std::false_type{};
361 
362  template<typename T>
363  struct allocator_has_recommended_allocation_size_impl<T,
364  void_t<decltype(std::declval<allocator_size_type_t<T>&>()
365  = std::declval<const T&>().recommended_allocation_size( std::declval<allocator_size_type_t<T>>() ))
366  >
367  > : std::true_type{};
368 
369  //----------------------------------------------------------------------
370 
371  template<typename T, typename = void>
372  struct allocator_has_owns_impl : std::false_type{};
373 
374  template<typename T>
375  struct allocator_has_owns_impl<T,
376  void_t<decltype(std::declval<bool&>()
377  = std::declval<const T&>().owns( std::declval<allocator_const_pointer_t<T>>() ))
378  >
379  > : std::true_type{};
380 
381  //----------------------------------------------------------------------
382 
383  template<typename T, typename = void>
384  struct allocator_has_info_impl : std::false_type{};
385 
386  template<typename T>
387  struct allocator_has_info_impl<T,
388  void_t<decltype( std::declval<allocator_info>() = std::declval<const T&>().info() )>
389  > : std::true_type{};
390 
391  //----------------------------------------------------------------------
392 
393  template<typename T, typename = void>
394  struct allocator_has_is_unbounded_impl : std::false_type{};
395 
396  template<typename T>
397  struct allocator_has_is_unbounded_impl<T,
398  void_t<decltype( std::declval<bool&>()
399  = std::declval<const T&>().is_unbounded())
400  >
401  > : std::true_type{};
402 
403  //----------------------------------------------------------------------
404 
405  template<typename T, typename = void>
406  struct allocator_has_max_size_impl : std::false_type{};
407 
408  template<typename T>
409  struct allocator_has_max_size_impl<T,
410  void_t<decltype( std::declval<allocator_size_type_t<T>&>()
411  = std::declval<const T&>().max_size())
412  >
413  > : std::true_type{};
414 
415  //----------------------------------------------------------------------
416 
417  template<typename T, typename = void>
418  struct allocator_has_min_size_impl : std::false_type{};
419 
420  template<typename T>
421  struct allocator_has_min_size_impl<T,
422  void_t<decltype( std::declval<allocator_size_type_t<T>&>()
423  = std::declval<const T&>().min_size())
424  >
425  > : std::true_type{};
426 
427  //----------------------------------------------------------------------
428 
429  template<typename T, typename = void>
430  struct allocator_default_alignment_impl
431  : std::integral_constant<allocator_size_type_t<T>,1>{};
432 
433  template<typename T>
434  struct allocator_default_alignment_impl<T,
435  void_t<decltype(T::default_alignment)>>
436  : T::default_alignment{};
437 
438  //----------------------------------------------------------------------
439 
440  template<typename T, typename = void>
441  struct allocator_max_alignment_impl
442  : std::integral_constant<allocator_size_type_t<T>,alignof(std::max_align_t)>{};
443 
444  template<typename T>
445  struct allocator_max_alignment_impl<T,
446  void_t<decltype(T::max_alignment)>>
447  : std::integral_constant<allocator_size_type_t<T>,alignof(std::max_align_t)>{};
448 
449  //----------------------------------------------------------------------
450 
451  template<typename T, typename = void>
452  struct allocator_has_expand : std::false_type{};
453 
454  template<typename T>
455  struct allocator_has_expand<T,
456  void_t<decltype(std::declval<bool&>()
457  = std::declval<T&>().expand( std::declval<allocator_pointer_t<T>&>(),
458  std::declval<allocator_size_type_t<T>>() ))
459  >
460  > : std::true_type{};
461 
462  } // namespace detail
463 
470  template<typename T>
472  : detail::allocator_has_try_allocate_hint_impl<T>{};
473 
478  template<typename T>
479  constexpr bool allocator_has_try_allocate_hint_v
481 
482  //-------------------------------------------------------------------------
483 
489  template<typename T>
491  : detail::allocator_has_allocate_impl<T>{};
492 
497  template<typename T>
498  constexpr bool allocator_has_allocate_v
500 
501  //-------------------------------------------------------------------------
502 
508  template<typename T>
510  : detail::allocator_has_allocate_hint_impl<T>{};
511 
516  template<typename T>
517  constexpr bool allocator_has_allocate_hint_v
519 
520  //-------------------------------------------------------------------------
521 
527  template<typename T, typename U, typename...Args>
529  : detail::allocator_has_construct_impl<T,U,detail::allocator_type_list<Args...>>{};
530 
535  template<typename T, typename U, typename...Args>
536  constexpr bool allocator_has_construct_v
537  = allocator_has_construct<T,U,Args...>::value;
538 
539  //-------------------------------------------------------------------------
540 
546  template<typename T, typename U, typename...Args>
548  : detail::allocator_has_make_impl<T,U,detail::allocator_type_list<Args...>>{};
549 
554  template<typename T, typename U, typename...Args>
555  constexpr bool allocator_has_make_v
556  = allocator_has_make<T,U,Args...>::value;
557 
558  //-------------------------------------------------------------------------
559 
565  template<typename T, typename U, typename...Args>
567  : detail::allocator_has_make_array_impl<T,U,detail::allocator_type_list<Args...>>{};
568 
573  template<typename T, typename U, typename...Args>
574  constexpr bool allocator_has_make_array_v
575  = allocator_has_make_array<T,U,Args...>::value;
576 
577  //-------------------------------------------------------------------------
578 
585  template<typename T>
587  : detail::allocator_has_deallocate_all_impl<T>{};
588 
593  template<typename T>
594  constexpr bool allocator_can_truncate_deallocations_v = allocator_can_truncate_deallocations<T>::value;
595 
596  //-------------------------------------------------------------------------
597 
604  template<typename T, typename U>
606  : detail::allocator_has_destroy_impl<T,U>{};
607 
612  template<typename T, typename U>
613  constexpr bool allocator_has_destroy_v
615 
616  //-------------------------------------------------------------------------
617 
624  template<typename T, typename U>
626  : detail::allocator_has_dispose_impl<T,U>{};
627 
632  template<typename T, typename U>
633  constexpr bool allocator_has_dispose_v
635 
636  //-------------------------------------------------------------------------
637 
644  template<typename T, typename U>
646  : detail::allocator_has_dispose_array_impl<T,U>{};
647 
652  template<typename T, typename U>
653  constexpr bool allocator_has_dispose_array_v
655 
656  //-------------------------------------------------------------------------
657 
664  template<typename T>
666  : detail::allocator_has_recommended_allocation_size_impl<T>{};
667 
672  template<typename T>
673  constexpr bool allocator_has_recommended_allocation_size_v
675 
676  //-------------------------------------------------------------------------
677 
683  template<typename T>
685  : detail::allocator_has_owns_impl<T>{};
686 
691  template<typename T>
692  constexpr bool allocator_knows_ownership_v = allocator_knows_ownership<T>::value;
693 
694  //-------------------------------------------------------------------------
695 
701  template<typename T>
703  : detail::allocator_has_info_impl<T>{};
704 
709  template<typename T>
710  constexpr bool allocator_has_info_v = allocator_has_info<T>::value;
711 
712  //-------------------------------------------------------------------------
713 
719  template<typename T>
721  : detail::allocator_has_is_unbounded_impl<T>{};
722 
727  template<typename T>
728  constexpr bool allocator_has_is_unbounded_v = allocator_has_is_unbounded<T>::value;
729 
730  //-------------------------------------------------------------------------
731 
737  template<typename T>
739  : detail::allocator_has_max_size_impl<T>{};
740 
745  template<typename T>
746  constexpr bool allocator_has_max_size_v = allocator_has_max_size<T>::value;
747 
748  //-------------------------------------------------------------------------
749 
755  template<typename T>
757  : detail::allocator_has_min_size_impl<T>{};
758 
763  template<typename T>
764  constexpr bool allocator_has_min_size_v = allocator_has_min_size<T>::value;
765 
766  //-------------------------------------------------------------------------
767 
773  template<typename T>
775  : detail::allocator_default_alignment_impl<T>{};
776 
781  template<typename T>
782  constexpr allocator_size_type_t<T> allocator_default_alignment_v = allocator_default_alignment<T>::value;
783 
784  //-------------------------------------------------------------------------
785 
791  template<typename T>
793  : detail::allocator_max_alignment_impl<T>{};
794 
799  template<typename T>
800  constexpr allocator_size_type_t<T> allocator_max_alignment_v = allocator_max_alignment<T>::value;
801 
802  //-------------------------------------------------------------------------
803 
810  template<typename T>
812  : detail::allocator_has_expand<T>{};
813 
818  template<typename T>
819  constexpr bool allocator_has_expand_v = allocator_has_expand<T>::value;
820 
821  //-------------------------------------------------------------------------
822 
829  template<typename T>
830  struct is_allocator : std::integral_constant<bool,
831  detail::allocator_has_try_allocate_impl<T>::value &&
832  detail::allocator_has_deallocate_impl<T>::value
833  >{};
834 
839  template<typename T>
840  constexpr bool is_allocator_v = is_allocator<T>::value;
841 
842  } // namespace memory
843 } // namespace bit
844 
845 #endif /* BIT_MEMORY_CONCEPTS_ALLOCATOR_HPP */
Type-trait to determine whether T has a &#39;dispose&#39; function.
Definition: Allocator.hpp:625
Type-trait to determine whether T has a &#39;min_size&#39; function.
Definition: Allocator.hpp:756
Type-trait to determine whether T has an &#39;info&#39; function.
Definition: Allocator.hpp:702
STL namespace.
Type-trait to determine whether T has a &#39;max_size&#39; function.
Definition: Allocator.hpp:738
Type-trait to determine whether T has a &#39;deallocate_all&#39; function.
Definition: Allocator.hpp:586
Type-trait to determine the default alignment of the given T.
Definition: Allocator.hpp:774
Type-trait to determine whether T has a &#39;make_array&#39; function.
Definition: Allocator.hpp:566
Type-trait to determine whether T satisfies the minimum requirements to be an Allocator.
Definition: Allocator.hpp:830
Type-trait to determine whether T has an &#39;allocate&#39; function.
Definition: Allocator.hpp:490
Type-trait to determine whether T has a &#39;try_allocate&#39; function that accepts a hint.
Definition: Allocator.hpp:471
Type-trait to determine the maximum alignment of the given T.
Definition: Allocator.hpp:792
Type-trait to determine whether T has a &#39;destroy&#39; function.
Definition: Allocator.hpp:605
Type-trait to determine whether T has a &#39;construct&#39; function.
Definition: Allocator.hpp:528
Type-trait to determine whether T has a &#39;dispose_array&#39; function.
Definition: Allocator.hpp:645
Type trait to determine whether the allocator has the expand function.
Definition: Allocator.hpp:811
Type-trait to determine whether T has a &#39;make&#39; function.
Definition: Allocator.hpp:547
Type-trait to determine whether T has an &#39;allocate&#39; function.
Definition: Allocator.hpp:509
Type-trait to determine whether T has an &#39;owns&#39; function.
Definition: Allocator.hpp:684
Type-trait to determine whether T has a &#39;is_unbounded&#39; function.
Definition: Allocator.hpp:720