/* Memory utilities for OctaSTD. * * This file is part of OctaSTD. See COPYING.md for futher information. */ #ifndef OCTA_MEMORY_H #define OCTA_MEMORY_H #include #include "octa/new.h" #include "octa/utility.h" #include "octa/type_traits.h" namespace octa { /* address of */ template constexpr _T *address_of(_T &__v) { return reinterpret_cast<_T *>(&const_cast (reinterpret_cast(__v))); } /* pointer traits */ template struct __OctaHasElement { template static int __test(...); template static char __test(typename _U::Element * = 0); static constexpr bool value = (sizeof(__test<_T>(0)) == 1); }; template::value> struct __OctaPtrTraitsElementType; template struct __OctaPtrTraitsElementType<_T, true> { typedef typename _T::Element Type; }; template class _T, typename _U, typename ..._A> struct __OctaPtrTraitsElementType<_T<_U, _A...>, true> { typedef typename _T<_U, _A...>::Element Type; }; template class _T, typename _U, typename ..._A> struct __OctaPtrTraitsElementType<_T<_U, _A...>, false> { typedef _U Type; }; template struct __OctaHasDifference { template static int __test(...); template static char __test(typename _U::Difference * = 0); static constexpr bool value = (sizeof(__test<_T>(0)) == 1); }; template::value> struct __OctaPtrTraitsDifferenceType { typedef ptrdiff_t Type; }; template struct __OctaPtrTraitsDifferenceType<_T, true> { typedef typename _T::Difference Type; }; template struct __OctaHasRebind { template static int __test(...); template static char __test(typename _V::template Rebind<_U> * = 0); static constexpr bool value = (sizeof(__test<_T>(0)) == 1); }; template::value> struct __OctaPtrTraitsRebindType { typedef typename _T::template Rebind<_U> Type; }; template class _T, typename _U, typename ..._A, typename _V > struct __OctaPtrTraitsRebindType<_T<_U, _A...>, _V, true> { typedef typename _T<_U, _A...>::template Rebind<_V> Type; }; template class _T, typename _U, typename ..._A, typename _V > struct __OctaPtrTraitsRebindType<_T<_U, _A...>, _V, false> { typedef _T<_V, _A...> Type; }; template struct __OctaPtrTraitsPointer { typedef _T Type; }; template struct __OctaPtrTraitsPointer<_T *> { typedef _T *Type; }; template using Pointer = typename __OctaPtrTraitsPointer<_T>::Type; template struct __OctaPtrTraitsElement { typedef typename __OctaPtrTraitsElementType<_T>::Type Type; }; template struct __OctaPtrTraitsElement<_T *> { typedef _T Type; }; template using PointerElement = typename __OctaPtrTraitsElement<_T>::Type; template struct __OctaPtrTraitsDifference { typedef typename __OctaPtrTraitsDifferenceType<_T>::Type Type; }; template struct __OctaPtrTraitsDifference<_T *> { typedef ptrdiff_t Type; }; template using PointerDifference = typename __OctaPtrTraitsDifference<_T>::Type; template struct __OctaPtrTraitsRebind { using type = typename __OctaPtrTraitsRebindType<_T, _U>::Type; }; template struct __OctaPtrTraitsRebind<_T *, _U> { using type = _U *; }; template using PointerRebind = typename __OctaPtrTraitsRebind<_T, _U>::Type; struct __OctaPtrTraitsNat {}; template struct __OctaPtrTraitsPointerTo { static _T pointer_to(octa::Conditional< octa::IsVoid>::value, __OctaPtrTraitsNat, PointerElement<_T> > &__r) { return _T::pointer_to(__r); } }; template struct __OctaPtrTraitsPointerTo<_T *> { static _T pointer_to(octa::Conditional< octa::IsVoid<_T>::value, __OctaPtrTraitsNat, _T > &__r) { return octa::address_of(__r); } }; template static _T pointer_to(octa::Conditional< octa::IsVoid>::value, __OctaPtrTraitsNat, PointerElement<_T> > &__r) { return __OctaPtrTraitsPointerTo<_T>::pointer_to(__r); } /* default deleter */ template struct DefaultDelete { constexpr DefaultDelete() = default; template DefaultDelete(const DefaultDelete<_U> &) {}; void operator()(_T *__p) const { delete __p; } }; template struct DefaultDelete<_T[]> { constexpr DefaultDelete() = default; template DefaultDelete(const DefaultDelete<_U[]> &) {}; void operator()(_T *__p) const { delete[] __p; } template void operator()(_U *) const = delete; }; /* box */ template::value> struct __OctaBoxPair; template struct __OctaBoxPair<_T, _U, false> { /* non-empty deleter */ _T *__ptr; private: _U __del; public: template __OctaBoxPair(_T *__ptr, _D &&__dltr): __ptr(__ptr), __del(octa::forward<_D>(__dltr)) {} _U &get_deleter() { return __del; } const _U &get_deleter() const { return __del; } void swap(__OctaBoxPair &__v) { octa::swap(__ptr, __v.__ptr); octa::swap(__del, __v.__del); } }; template struct __OctaBoxPair<_T, _U, true>: _U { /* empty deleter */ _T *__ptr; template __OctaBoxPair(_T *__ptr, _D &&__dltr): _U(octa::forward<_D>(__dltr)), __ptr(__ptr) {} _U &get_deleter() { return *this; } const _U &get_deleter() const { return *this; } void swap(__OctaBoxPair &__v) { octa::swap(__ptr, __v.__ptr); } }; template static int __octa_ptr_test(...); template static char __octa_ptr_test(typename _T::Pointer * = 0); template struct __OctaHasPtr: octa::IntegralConstant(0)) == 1) > {}; template::value> struct __OctaPointerBase { typedef typename _D::Pointer Type; }; template struct __OctaPointerBase<_T, _D, false> { typedef _T *Type; }; template struct __OctaPointer { typedef typename __OctaPointerBase<_T, octa::RemoveReference<_D>>::Type Type; }; template> struct Box { typedef _T Element; typedef _D Deleter; typedef typename __OctaPointer<_T, _D>::Type Pointer; private: struct __OctaNat { int __x; }; typedef RemoveReference<_D> &_D_ref; typedef const RemoveReference<_D> &_D_cref; public: constexpr Box(): __stor(nullptr, _D()) { static_assert(!octa::IsPointer<_D>::value, "Box constructed with null fptr deleter"); } constexpr Box(nullptr_t): __stor(nullptr, _D()) { static_assert(!octa::IsPointer<_D>::value, "Box constructed with null fptr deleter"); } explicit Box(Pointer __p): __stor(__p, _D()) { static_assert(!octa::IsPointer<_D>::value, "Box constructed with null fptr deleter"); } Box(Pointer __p, octa::Conditional::value, _D, octa::AddLvalueReference > __d): __stor(__p, __d) {} Box(Pointer __p, octa::RemoveReference<_D> &&__d): __stor(__p, octa::move(__d)) { static_assert(!octa::IsReference<_D>::value, "rvalue deleter cannot be a ref"); } Box(Box &&__u): __stor(__u.release(), octa::forward<_D>(__u.get_deleter())) {} template Box(Box<_TT, _DD> &&__u, octa::EnableIf::value && octa::IsConvertible::Pointer, Pointer>::value && octa::IsConvertible<_DD, _D>::value && (!octa::IsReference<_D>::value || octa::IsSame<_D, _DD>::value) > = __OctaNat()): __stor(__u.release(), octa::forward<_DD>(__u.get_deleter())) {} Box &operator=(Box &&__u) { reset(__u.release()); __stor.get_deleter() = octa::forward<_D>(__u.get_deleter()); return *this; } template EnableIf::value && octa::IsConvertible::Pointer, Pointer>::value && octa::IsAssignable<_D &, _DD &&>::value, Box & > operator=(Box<_TT, _DD> &&__u) { reset(__u.release()); __stor.get_deleter() = octa::forward<_DD>(__u.get_deleter()); return *this; } Box &operator=(nullptr_t) { reset(); return *this; } ~Box() { reset(); } octa::AddLvalueReference<_T> operator*() const { return *__stor.__ptr; } Pointer operator->() const { return __stor.__ptr; } explicit operator bool() const { return __stor.__ptr != nullptr; } Pointer get() const { return __stor.__ptr; } _D_ref get_deleter() { return __stor.get_deleter(); } _D_cref get_deleter() const { return __stor.get_deleter(); } Pointer release() { Pointer __p = __stor.__ptr; __stor.__ptr = nullptr; return __p; } void reset(Pointer __p = nullptr) { Pointer __tmp = __stor.__ptr; __stor.__ptr = __p; if (__tmp) __stor.get_deleter()(__tmp); } void swap(Box &__u) { __stor.swap(__u.__stor); } private: __OctaBoxPair<_T, _D> __stor; }; template>, octa::RemoveCv> >::value> struct __OctaSameOrLessCvQualifiedBase: octa::IsConvertible<_T, _U> {}; template struct __OctaSameOrLessCvQualifiedBase<_T, _U, false>: octa::False {}; template::value || octa::IsSame<_T, _U>::value || __OctaHasElement<_T>::value > struct __OctaSameOrLessCvQualified: __OctaSameOrLessCvQualifiedBase<_T, _U> {}; template struct __OctaSameOrLessCvQualified<_T, _U, false>: octa::False {}; template struct Box<_T[], _D> { typedef _T Element; typedef _D Deleter; typedef typename __OctaPointer<_T, _D>::Type Pointer; private: struct __OctaNat { int __x; }; typedef RemoveReference<_D> &_D_ref; typedef const RemoveReference<_D> &_D_cref; public: constexpr Box(): __stor(nullptr, _D()) { static_assert(!octa::IsPointer<_D>::value, "Box constructed with null fptr deleter"); } constexpr Box(nullptr_t): __stor(nullptr, _D()) { static_assert(!octa::IsPointer<_D>::value, "Box constructed with null fptr deleter"); } template explicit Box(_U __p, octa::EnableIf< __OctaSameOrLessCvQualified<_U, Pointer>::value, __OctaNat > = __OctaNat()): __stor(__p, _D()) { static_assert(!octa::IsPointer<_D>::value, "Box constructed with null fptr deleter"); } template Box(_U __p, octa::Conditional< octa::IsReference<_D>::value, _D, AddLvalueReference > __d, octa::EnableIf<__OctaSameOrLessCvQualified<_U, Pointer>::value, __OctaNat> = __OctaNat()): __stor(__p, __d) {} Box(nullptr_t, octa::Conditional::value, _D, AddLvalueReference > __d): __stor(nullptr, __d) {} template Box(_U __p, octa::RemoveReference<_D> &&__d, octa::EnableIf< __OctaSameOrLessCvQualified<_U, Pointer>::value, __OctaNat > = __OctaNat()): __stor(__p, octa::move(__d)) { static_assert(!octa::IsReference<_D>::value, "rvalue deleter cannot be a ref"); } Box(nullptr_t, octa::RemoveReference<_D> &&__d): __stor(nullptr, octa::move(__d)) { static_assert(!octa::IsReference<_D>::value, "rvalue deleter cannot be a ref"); } Box(Box &&__u): __stor(__u.release(), octa::forward<_D>(__u.get_deleter())) {} template Box(Box<_TT, _DD> &&__u, EnableIf::value && __OctaSameOrLessCvQualified::Pointer, Pointer>::value && octa::IsConvertible<_DD, _D>::value && (!octa::IsReference<_D>::value || octa::IsSame<_D, _DD>::value)> = __OctaNat() ): __stor(__u.release(), octa::forward<_DD>(__u.get_deleter())) {} Box &operator=(Box &&__u) { reset(__u.release()); __stor.get_deleter() = octa::forward<_D>(__u.get_deleter()); return *this; } template EnableIf::value && __OctaSameOrLessCvQualified::Pointer, Pointer>::value && IsAssignable<_D &, _DD &&>::value, Box & > operator=(Box<_TT, _DD> &&__u) { reset(__u.release()); __stor.get_deleter() = octa::forward<_DD>(__u.get_deleter()); return *this; } Box &operator=(nullptr_t) { reset(); return *this; } ~Box() { reset(); } octa::AddLvalueReference<_T> operator[](size_t __idx) const { return __stor.__ptr[__idx]; } explicit operator bool() const { return __stor.__ptr != nullptr; } Pointer get() const { return __stor.__ptr; } _D_ref get_deleter() { return __stor.get_deleter(); } _D_cref get_deleter() const { return __stor.get_deleter(); } Pointer release() { Pointer __p = __stor.__ptr; __stor.__ptr = nullptr; return __p; } template EnableIf< __OctaSameOrLessCvQualified<_U, Pointer>::value, void > reset(_U __p) { Pointer __tmp = __stor.__ptr; __stor.__ptr = __p; if (__tmp) __stor.get_deleter()(__tmp); } void reset(nullptr_t) { Pointer __tmp = __stor.__ptr; __stor.__ptr = nullptr; if (__tmp) __stor.get_deleter()(__tmp); } void reset() { reset(nullptr); } void swap(Box &__u) { __stor.swap(__u.__stor); } private: __OctaBoxPair<_T, _D> __stor; }; template struct __OctaBoxIf { typedef Box<_T> __OctaBox; }; template struct __OctaBoxIf<_T[]> { typedef Box<_T[]> __OctaBoxUnknownSize; }; template struct __OctaBoxIf<_T[_N]> { typedef void __OctaBoxKnownSize; }; template typename __OctaBoxIf<_T>::__OctaBox make_box(_A &&...__args) { return Box<_T>(new _T(octa::forward<_A>(__args)...)); } template typename __OctaBoxIf<_T>::__OctaBoxUnknownSize make_box(size_t __n) { return Box<_T>(new octa::RemoveExtent<_T>[__n]()); } template typename __OctaBoxIf<_T>::__OctaBoxKnownSize make_box(_A &&...__args) = delete; /* allocator */ template struct Allocator; template<> struct Allocator { typedef void Value; typedef void *Pointer; typedef const void *ConstPointer; template using Rebind = Allocator<_U>; }; template<> struct Allocator { typedef const void Value; typedef const void *Pointer; typedef const void *ConstPointer; template using Rebind = Allocator<_U>; }; template struct Allocator { typedef size_t Size; typedef ptrdiff_t Difference; typedef _T Value; typedef _T &Reference; typedef const _T &ConstReference; typedef _T *Pointer; typedef const _T *ConstPointer; template using Rebind = Allocator<_U>; Pointer address(Reference __v) const { return address_of(__v); }; ConstPointer address(ConstReference __v) const { return address_of(__v); }; Size max_size() const { return Size(~0) / sizeof(_T); } Pointer allocate(Size __n, Allocator::ConstPointer = nullptr) { return (Pointer) ::new uchar[__n * sizeof(_T)]; } void deallocate(Pointer __p, Size) { ::delete[] (uchar *) __p; } template void construct(_U *__p, _A &&...__args) { ::new((void *)__p) _U(octa::forward<_A>(__args)...); } void destroy(Pointer __p) { __p->~_T(); } }; template struct Allocator { typedef size_t Size; typedef ptrdiff_t Difference; typedef const _T Value; typedef const _T &Reference; typedef const _T &ConstReference; typedef const _T *Pointer; typedef const _T *ConstPointer; template using Rebind = Allocator<_U>; ConstPointer address(ConstReference __v) const { return address_of(__v); }; Size max_size() const { return Size(~0) / sizeof(_T); } Pointer allocate(Size __n, Allocator::ConstPointer = nullptr) { return (Pointer) ::new uchar[__n * sizeof(_T)]; } void deallocate(Pointer __p, Size) { ::delete[] (uchar *) __p; } template void construct(_U *__p, _A &&...__args) { ::new((void *)__p) _U(octa::forward<_A>(__args)...); } void destroy(Pointer __p) { __p->~_T(); } }; template bool operator==(const Allocator<_T> &, const Allocator<_U> &) { return true; } template bool operator!=(const Allocator<_T> &, const Allocator<_U> &) { return false; } /* allocator traits - modeled after libc++ */ template struct __OctaConstPtrTest { template static char __test( typename _U::ConstPointer * = 0); template static int __test(...); static constexpr bool value = (sizeof(__test<_T>(0)) == 1); }; template::value> struct __OctaConstPointer { typedef typename _A::ConstPointer Type; }; template struct __OctaConstPointer<_T, _P, _A, false> { typedef PointerRebind<_P, const _T> Type; }; template struct __OctaVoidPtrTest { template static char __test( typename _U::VoidPointer * = 0); template static int __test(...); static constexpr bool value = (sizeof(__test<_T>(0)) == 1); }; template::value> struct __OctaVoidPointer { typedef typename _A::VoidPointer Type; }; template struct __OctaVoidPointer<_P, _A, false> { typedef PointerRebind<_P, void> Type; }; template struct __OctaConstVoidPtrTest { template static char __test( typename _U::ConstVoidPointer * = 0); template static int __test(...); static constexpr bool value = (sizeof(__test<_T>(0)) == 1); }; template::value> struct __OctaConstVoidPointer { typedef typename _A::ConstVoidPointer Type; }; template struct __OctaConstVoidPointer<_P, _A, false> { typedef PointerRebind<_P, const void> Type; }; template struct __OctaSizeTest { template static char __test(typename _U::Size * = 0); template static int __test(...); static constexpr bool value = (sizeof(__test<_T>(0)) == 1); }; template::value> struct __OctaSize { typedef octa::MakeUnsigned<_D> Type; }; template struct __OctaSize<_A, _D, true> { typedef typename _A::Size Type; }; /* allocator type traits */ template using AllocatorType = _A; template using AllocatorValue = typename AllocatorType<_A>::Value; template using AllocatorPointer = typename __OctaPointer< AllocatorValue<_A>, AllocatorType <_A> >::Type; template using AllocatorConstPointer = typename __OctaConstPointer< AllocatorValue<_A>, AllocatorPointer<_A>, AllocatorType<_A> >::Type; template using AllocatorVoidPointer = typename __OctaVoidPointer< AllocatorPointer<_A>, AllocatorType<_A> >::Type; template using AllocatorConstVoidPointer = typename __OctaConstVoidPointer< AllocatorPointer<_A>, AllocatorType<_A> >::Type; /* allocator difference */ template struct __OctaDiffTest { template static char __test(typename _U::Difference * = 0); template static int __test(...); static constexpr bool value = (sizeof(__test<_T>(0)) == 1); }; template::value> struct __OctaAllocDifference { typedef PointerDifference<_P> Type; }; template struct __OctaAllocDifference<_A, _P, true> { typedef typename _A::Difference Type; }; template using AllocatorDifference = typename __OctaAllocDifference< _A, AllocatorPointer<_A> >::Type; /* allocator size */ template using AllocatorSize = typename __OctaSize< _A, AllocatorDifference<_A> >::Type; /* allocator rebind */ template::value> struct __OctaAllocTraitsRebindType { typedef typename _T::template Rebind<_U> Type; }; template class _A, typename _T, typename ..._Args, typename _U > struct __OctaAllocTraitsRebindType<_A<_T, _Args...>, _U, true> { typedef typename _A<_T, _Args...>::template Rebind<_U> Type; }; template class _A, typename _T, typename ..._Args, typename _U > struct __OctaAllocTraitsRebindType<_A<_T, _Args...>, _U, false> { typedef _A<_U, _Args...> Type; }; template using AllocatorRebind = typename __OctaAllocTraitsRebindType< AllocatorType<_A>, _T >::Type; /* allocator propagate on container copy assignment */ template struct __OctaPropagateOnContainerCopyAssignmentTest { template static char __test( typename _U::PropagateOnContainerCopyAssignment * = 0); template static int __test(...); static constexpr bool value = (sizeof(__test<_T>(0)) == 1); }; template::value> struct __OctaPropagateOnContainerCopyAssignment { typedef octa::False Type; }; template struct __OctaPropagateOnContainerCopyAssignment<_A, true> { typedef typename _A::PropagateOnContainerCopyAssignment Type; }; template using PropagateOnContainerCopyAssignment = typename __OctaPropagateOnContainerCopyAssignment<_A>::Type; /* allocator propagate on container move assignment */ template struct __OctaPropagateOnContainerMoveAssignmentTest { template static char __test( typename _U::PropagateOnContainerMoveAssignment * = 0); template static int __test(...); static constexpr bool value = (sizeof(__test<_T>(0)) == 1); }; template::value> struct __OctaPropagateOnContainerMoveAssignment { typedef octa::False Type; }; template struct __OctaPropagateOnContainerMoveAssignment<_A, true> { typedef typename _A::PropagateOnContainerMoveAssignment Type; }; template using PropagateOnContainerMoveAssignment = typename __OctaPropagateOnContainerMoveAssignment<_A>::Type; /* allocator propagate on container swap */ template struct __OctaPropagateOnContainerSwapTest { template static char __test( typename _U::PropagateOnContainerSwap * = 0); template static int __test(...); static constexpr bool value = (sizeof(__test<_T>(0)) == 1); }; template::value> struct __OctaPropagateOnContainerSwap { typedef octa::False Type; }; template struct __OctaPropagateOnContainerSwap<_A, true> { typedef typename _A::PropagateOnContainerSwap Type; }; template using PropagateOnContainerSwap = typename __OctaPropagateOnContainerSwap<_A>::Type; /* allocator is always equal */ template struct __OctaIsAlwaysEqualTest { template static char __test( typename _U::IsAlwaysEqual * = 0); template static int __test(...); static constexpr bool value = (sizeof(__test<_T>(0)) == 1); }; template::value> struct __OctaIsAlwaysEqual { typedef typename octa::IsEmpty<_A>::Type Type; }; template struct __OctaIsAlwaysEqual<_A, true> { typedef typename _A::IsAlwaysEqual Type; }; template using IsAlwaysEqual = typename __OctaIsAlwaysEqual<_A>::Type; /* allocator allocate */ template inline AllocatorPointer<_A> allocator_allocate(_A &__a, AllocatorSize<_A> __n) { return __a.allocate(__n); } template auto __octa_allocate_hint_test(_A &&__a, _S &&__sz, _CVP &&__p) -> decltype(__a.allocate(__sz, __p), octa::True()); template auto __octa_allocate_hint_test(const _A &__a, _S &&__sz, _CVP &&__p) -> octa::False; template struct __OctaAllocateHintTest: octa::IntegralConstant(), octa::declval<_S>(), octa::declval<_CVP>())), octa::True >::value > {}; template inline AllocatorPointer<_A> __octa_allocate(_A &__a, AllocatorSize<_A> __n, AllocatorConstVoidPointer<_A> __h, octa::True) { return __a.allocate(__n, __h); } template inline AllocatorPointer<_A> __octa_allocate(_A &__a, AllocatorSize<_A> __n, AllocatorConstVoidPointer<_A>, octa::False) { return __a.allocate(__n); } template inline AllocatorPointer<_A> allocator_allocate(_A &__a, AllocatorSize<_A> __n, AllocatorConstVoidPointer<_A> __h) { return __octa_allocate(__a, __n, __h, __OctaAllocateHintTest< _A, AllocatorSize<_A>, AllocatorConstVoidPointer<_A> >()); } /* allocator deallocate */ template inline void allocator_deallocate(_A &__a, AllocatorPointer<_A> __p, AllocatorSize<_A> __n) { __a.deallocate(__p, __n); } /* allocator construct */ template auto __octa_construct_test(_A &&__a, _T *__p, _Args &&...__args) -> decltype(__a.construct(__p, octa::forward<_Args>(__args)...), octa::True()); template auto __octa_construct_test(const _A &__a, _T *__p, _Args &&...__args) -> octa::False; template struct __OctaConstructTest: octa::IntegralConstant(), octa::declval<_T>(), octa::declval<_Args>()...)), octa::True >::value > {}; template inline void __octa_construct(octa::True, _A &__a, _T *__p, _Args &&...__args) { __a.construct(__p, octa::forward<_Args>(__args)...); } template inline void __octa_construct(octa::False, _A &, _T *__p, _Args &&...__args) { ::new ((void *)__p) _T(octa::forward<_Args>(__args)...); } template inline void allocator_construct(_A &__a, _T *__p, _Args &&...__args) { __octa_construct(__OctaConstructTest<_A, _T *, _Args...>(), __a, __p, octa::forward<_Args>(__args)...); } /* allocator destroy */ template auto __octa_destroy_test(_A &&__a, _P &&__p) -> decltype(__a.destroy(__p), octa::True()); template auto __octa_destroy_test(const _A &__a, _P &&__p) -> octa::False; template struct __OctaDestroyTest: octa::IntegralConstant(), octa::declval<_P>())), octa::True >::value > {}; template inline void __octa_destroy(octa::True, _A &__a, _T *__p) { __a.destroy(__p); } template inline void __octa_destroy(octa::False, _A &, _T *__p) { __p->~_T(); } template inline void allocator_destroy(_A &__a, _T *__p) { __octa_destroy(__OctaDestroyTest<_A, _T *>(), __a, __p); } /* allocator max size */ template auto __octa_alloc_max_size_test(_A &&__a) -> decltype(__a.max_size(), octa::True()); template auto __octa_alloc_max_size_test(const _A &__a) -> octa::False; template struct __OctaAllocMaxSizeTest: octa::IntegralConstant())), octa::True >::value > {}; template inline AllocatorSize<_A> __octa_alloc_max_size(octa::True, const _A &__a) { return __a.max_size(); } template inline AllocatorSize<_A> __octa_alloc_max_size(octa::False, const _A &) { return AllocatorSize<_A>(~0); } template inline AllocatorSize<_A> allocator_max_size(const _A &__a) { return __octa_alloc_max_size(__OctaAllocMaxSizeTest(), __a); } /* allocator container copy */ template auto __octa_alloc_copy_test(_A &&__a) -> decltype(__a.container_copy(), octa::True()); template auto __octa_alloc_copy_test(const _A &__a) -> octa::False; template struct __OctaAllocCopyTest: octa::IntegralConstant())), octa::True >::value > {}; template inline AllocatorType<_A> __octa_alloc_container_copy(octa::True, const _A &__a) { return __a.container_copy(); } template inline AllocatorType<_A> __octa_alloc_container_copy(octa::False, const _A &__a) { return __a; } template inline AllocatorType<_A> allocator_container_copy(const _A &__a) { return __octa_alloc_container_copy(__OctaAllocCopyTest(), __a); } } #endif