/* 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 */ namespace detail { template struct HasElement { template static int test(...); template static char test(typename _U::Element * = 0); static constexpr bool value = (sizeof(test<_T>(0)) == 1); }; template::value> struct PointerElementBase; template struct PointerElementBase<_T, true> { typedef typename _T::Element Type; }; template class _T, typename _U, typename ..._A> struct PointerElementBase<_T<_U, _A...>, true> { typedef typename _T<_U, _A...>::Element Type; }; template class _T, typename _U, typename ..._A> struct PointerElementBase<_T<_U, _A...>, false> { typedef _U Type; }; template struct PointerElementType { typedef typename PointerElementBase<_T>::Type Type; }; template struct PointerElementType<_T *> { typedef _T Type; }; template struct HasDifference { template static int test(...); template static char test(typename _U::Difference * = 0); static constexpr bool value = (sizeof(test<_T>(0)) == 1); }; template::value> struct PointerDifferenceBase { typedef ptrdiff_t Type; }; template struct PointerDifferenceBase<_T, true> { typedef typename _T::Difference Type; }; template struct PointerDifferenceType { typedef typename PointerDifferenceBase<_T>::Type Type; }; template struct PointerDifferenceType<_T *> { typedef ptrdiff_t Type; }; template struct HasRebind { 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 PointerRebindBase { typedef typename _T::template Rebind<_U> Type; }; template class _T, typename _U, typename ..._A, typename _V > struct PointerRebindBase<_T<_U, _A...>, _V, true> { typedef typename _T<_U, _A...>::template Rebind<_V> Type; }; template class _T, typename _U, typename ..._A, typename _V > struct PointerRebindBase<_T<_U, _A...>, _V, false> { typedef _T<_V, _A...> Type; }; template struct PointerRebindType { using type = typename PointerRebindBase<_T, _U>::Type; }; template struct PointerRebindType<_T *, _U> { using type = _U *; }; template struct PointerPointer { typedef _T Type; }; template struct PointerPointer<_T *> { typedef _T *Type; }; } /*namespace detail */ template using Pointer = typename octa::detail::PointerPointer<_T>::Type; template using PointerElement = typename octa::detail::PointerElementType<_T>::Type; template using PointerDifference = typename octa::detail::PointerDifferenceType<_T>::Type; template using PointerRebind = typename octa::detail::PointerRebindType<_T, _U>::Type; /* pointer to */ namespace detail { struct PointerToNat {}; template struct PointerTo { static _T pointer_to(octa::Conditional< octa::IsVoid>::value, PointerToNat, PointerElement<_T> > &r) { return _T::pointer_to(r); } }; template struct PointerTo<_T *> { static _T pointer_to(octa::Conditional< octa::IsVoid<_T>::value, PointerToNat, _T > &r) { return octa::address_of(r); } }; } template static _T pointer_to(octa::Conditional< octa::IsVoid>::value, octa::detail::PointerToNat, PointerElement<_T> > &r) { return octa::detail::PointerTo<_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 */ namespace detail { template::value> struct BoxPair; template struct BoxPair<_T, _U, false> { /* non-empty deleter */ _T *p_ptr; private: _U p_del; public: template BoxPair(_T *ptr, _D &&dltr): p_ptr(ptr), p_del(octa::forward<_D>(dltr)) {} _U &get_deleter() { return p_del; } const _U &get_deleter() const { return p_del; } void swap(BoxPair &v) { octa::swap(p_ptr, v.p_ptr); octa::swap(p_del, v.p_del); } }; template struct BoxPair<_T, _U, true>: _U { /* empty deleter */ _T *p_ptr; template BoxPair(_T *ptr, _D &&dltr): _U(octa::forward<_D>(dltr)), p_ptr(ptr) {} _U &get_deleter() { return *this; } const _U &get_deleter() const { return *this; } void swap(BoxPair &v) { octa::swap(p_ptr, v.p_ptr); } }; template static int ptr_test(...); template static char ptr_test(typename _T::Pointer * = 0); template struct HasPtr: octa::IntegralConstant(0)) == 1) > {}; template::value> struct PointerBase { typedef typename _D::Pointer Type; }; template struct PointerBase<_T, _D, false> { typedef _T *Type; }; template struct PointerType { typedef typename PointerBase<_T, octa::RemoveReference<_D>>::Type Type; }; } /* namespace detail */ template> struct Box { typedef _T Element; typedef _D Deleter; typedef typename octa::detail::PointerType<_T, _D>::Type Pointer; private: struct Nat { int x; }; typedef RemoveReference<_D> &_D_ref; typedef const RemoveReference<_D> &_D_cref; public: constexpr Box(): p_stor(nullptr, _D()) { static_assert(!octa::IsPointer<_D>::value, "Box constructed with null fptr deleter"); } constexpr Box(nullptr_t): p_stor(nullptr, _D()) { static_assert(!octa::IsPointer<_D>::value, "Box constructed with null fptr deleter"); } explicit Box(Pointer p): 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): p_stor(p, d) {} Box(Pointer p, octa::RemoveReference<_D> &&d): p_stor(p, octa::move(d)) { static_assert(!octa::IsReference<_D>::value, "rvalue deleter cannot be a ref"); } Box(Box &&u): p_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) > = Nat()): p_stor(u.release(), octa::forward<_DD>(u.get_deleter())) {} Box &operator=(Box &&u) { reset(u.release()); p_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()); p_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 *p_stor.p_ptr; } Pointer operator->() const { return p_stor.p_ptr; } explicit operator bool() const { return p_stor.p_ptr != nullptr; } Pointer get() const { return p_stor.p_ptr; } _D_ref get_deleter() { return p_stor.get_deleter(); } _D_cref get_deleter() const { return p_stor.get_deleter(); } Pointer release() { Pointer p = p_stor.p_ptr; p_stor.p_ptr = nullptr; return p; } void reset(Pointer p = nullptr) { Pointer tmp = p_stor.p_ptr; p_stor.p_ptr = p; if (tmp) p_stor.get_deleter()(tmp); } void swap(Box &u) { p_stor.swap(u.p_stor); } private: octa::detail::BoxPair<_T, _D> p_stor; }; namespace detail { template>, octa::RemoveCv> >::value> struct SameOrLessCvQualifiedBase: octa::IsConvertible<_T, _U> {}; template struct SameOrLessCvQualifiedBase<_T, _U, false>: octa::False {}; template::value || octa::IsSame<_T, _U>::value || octa::detail::HasElement<_T>::value > struct SameOrLessCvQualified: SameOrLessCvQualifiedBase<_T, _U> {}; template struct SameOrLessCvQualified<_T, _U, false>: octa::False {}; } /* namespace detail */ template struct Box<_T[], _D> { typedef _T Element; typedef _D Deleter; typedef typename octa::detail::PointerType<_T, _D>::Type Pointer; private: struct Nat { int x; }; typedef RemoveReference<_D> &_D_ref; typedef const RemoveReference<_D> &_D_cref; public: constexpr Box(): p_stor(nullptr, _D()) { static_assert(!octa::IsPointer<_D>::value, "Box constructed with null fptr deleter"); } constexpr Box(nullptr_t): p_stor(nullptr, _D()) { static_assert(!octa::IsPointer<_D>::value, "Box constructed with null fptr deleter"); } template explicit Box(_U p, octa::EnableIf< octa::detail::SameOrLessCvQualified<_U, Pointer>::value, Nat > = Nat()): p_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::value, Nat> = Nat()): p_stor(p, d) {} Box(nullptr_t, octa::Conditional::value, _D, AddLvalueReference > d): p_stor(nullptr, d) {} template Box(_U p, octa::RemoveReference<_D> &&d, octa::EnableIf< octa::detail::SameOrLessCvQualified<_U, Pointer>::value, Nat > = Nat()): p_stor(p, octa::move(d)) { static_assert(!octa::IsReference<_D>::value, "rvalue deleter cannot be a ref"); } Box(nullptr_t, octa::RemoveReference<_D> &&d): p_stor(nullptr, octa::move(d)) { static_assert(!octa::IsReference<_D>::value, "rvalue deleter cannot be a ref"); } Box(Box &&u): p_stor(u.release(), octa::forward<_D>(u.get_deleter())) {} template Box(Box<_TT, _DD> &&u, EnableIf::value && octa::detail::SameOrLessCvQualified::Pointer, Pointer>::value && octa::IsConvertible<_DD, _D>::value && (!octa::IsReference<_D>::value || octa::IsSame<_D, _DD>::value)> = Nat() ): p_stor(u.release(), octa::forward<_DD>(u.get_deleter())) {} Box &operator=(Box &&u) { reset(u.release()); p_stor.get_deleter() = octa::forward<_D>(u.get_deleter()); return *this; } template EnableIf::value && octa::detail::SameOrLessCvQualified::Pointer, Pointer>::value && IsAssignable<_D &, _DD &&>::value, Box & > operator=(Box<_TT, _DD> &&u) { reset(u.release()); p_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 p_stor.p_ptr[idx]; } explicit operator bool() const { return p_stor.p_ptr != nullptr; } Pointer get() const { return p_stor.p_ptr; } _D_ref get_deleter() { return p_stor.get_deleter(); } _D_cref get_deleter() const { return p_stor.get_deleter(); } Pointer release() { Pointer p = p_stor.p_ptr; p_stor.p_ptr = nullptr; return p; } template EnableIf< octa::detail::SameOrLessCvQualified<_U, Pointer>::value, void > reset(_U p) { Pointer tmp = p_stor.p_ptr; p_stor.p_ptr = p; if (tmp) p_stor.get_deleter()(tmp); } void reset(nullptr_t) { Pointer tmp = p_stor.p_ptr; p_stor.p_ptr = nullptr; if (tmp) p_stor.get_deleter()(tmp); } void reset() { reset(nullptr); } void swap(Box &u) { p_stor.swap(u.p_stor); } private: octa::detail::BoxPair<_T, _D> p_stor; }; namespace detail { template struct BoxIf { typedef octa::Box<_T> Box; }; template struct BoxIf<_T[]> { typedef octa::Box<_T[]> BoxUnknownSize; }; template struct BoxIf<_T[_N]> { typedef void BoxKnownSize; }; } template typename octa::detail::BoxIf<_T>::Box make_box(_A &&...args) { return Box<_T>(new _T(octa::forward<_A>(args)...)); } template typename octa::detail::BoxIf<_T>::BoxUnknownSize make_box(size_t n) { return Box<_T>(new octa::RemoveExtent<_T>[n]()); } template typename octa::detail::BoxIf<_T>::BoxKnownSize 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++ */ namespace detail { template struct ConstPtrTest { template static char test( typename _U::ConstPointer * = 0); template static int test(...); static constexpr bool value = (sizeof(test<_T>(0)) == 1); }; template::value> struct ConstPointer { typedef typename _A::ConstPointer Type; }; template struct ConstPointer<_T, _P, _A, false> { typedef PointerRebind<_P, const _T> Type; }; template struct VoidPtrTest { template static char test( typename _U::VoidPointer * = 0); template static int test(...); static constexpr bool value = (sizeof(test<_T>(0)) == 1); }; template::value> struct VoidPointer { typedef typename _A::VoidPointer Type; }; template struct VoidPointer<_P, _A, false> { typedef PointerRebind<_P, void> Type; }; template struct ConstVoidPtrTest { template static char test( typename _U::ConstVoidPointer * = 0); template static int test(...); static constexpr bool value = (sizeof(test<_T>(0)) == 1); }; template::value> struct ConstVoidPointer { typedef typename _A::ConstVoidPointer Type; }; template struct ConstVoidPointer<_P, _A, false> { typedef PointerRebind<_P, const void> Type; }; template struct SizeTest { template static char test(typename _U::Size * = 0); template static int test(...); static constexpr bool value = (sizeof(test<_T>(0)) == 1); }; template::value> struct SizeBase { typedef octa::MakeUnsigned<_D> Type; }; template struct SizeBase<_A, _D, true> { typedef typename _A::Size Type; }; } /* namespace detail */ /* allocator type traits */ template using AllocatorType = _A; template using AllocatorValue = typename AllocatorType<_A>::Value; template using AllocatorPointer = typename octa::detail::PointerType< AllocatorValue<_A>, AllocatorType <_A> >::Type; template using AllocatorConstPointer = typename octa::detail::ConstPointer< AllocatorValue<_A>, AllocatorPointer<_A>, AllocatorType<_A> >::Type; template using AllocatorVoidPointer = typename octa::detail::VoidPointer< AllocatorPointer<_A>, AllocatorType<_A> >::Type; template using AllocatorConstVoidPointer = typename octa::detail::ConstVoidPointer< AllocatorPointer<_A>, AllocatorType<_A> >::Type; /* allocator difference */ namespace detail { template struct DiffTest { template static char test(typename _U::Difference * = 0); template static int test(...); static constexpr bool value = (sizeof(test<_T>(0)) == 1); }; template::value> struct AllocDifference { typedef PointerDifference<_P> Type; }; template struct AllocDifference<_A, _P, true> { typedef typename _A::Difference Type; }; } template using AllocatorDifference = typename octa::detail::AllocDifference< _A, AllocatorPointer<_A> >::Type; /* allocator size */ template using AllocatorSize = typename octa::detail::SizeBase< _A, AllocatorDifference<_A> >::Type; /* allocator rebind */ namespace detail { template::value> struct AllocTraitsRebindType { typedef typename _T::template Rebind<_U> Type; }; template class _A, typename _T, typename ..._Args, typename _U > struct AllocTraitsRebindType<_A<_T, _Args...>, _U, true> { typedef typename _A<_T, _Args...>::template Rebind<_U> Type; }; template class _A, typename _T, typename ..._Args, typename _U > struct AllocTraitsRebindType<_A<_T, _Args...>, _U, false> { typedef _A<_U, _Args...> Type; }; } /* namespace detail */ template using AllocatorRebind = typename octa::detail::AllocTraitsRebindType< AllocatorType<_A>, _T >::Type; /* allocator propagate on container copy assignment */ namespace detail { template struct PropagateOnContainerCopyAssignmentTest { template static char test( typename _U::PropagateOnContainerCopyAssignment * = 0); template static int test(...); static constexpr bool value = (sizeof(test<_T>(0)) == 1); }; template::value> struct PropagateOnContainerCopyAssignmentBase { typedef octa::False Type; }; template struct PropagateOnContainerCopyAssignmentBase<_A, true> { typedef typename _A::PropagateOnContainerCopyAssignment Type; }; } /* namespace detail */ template using PropagateOnContainerCopyAssignment = typename octa::detail::PropagateOnContainerCopyAssignmentBase<_A>::Type; /* allocator propagate on container move assignment */ namespace detail { template struct PropagateOnContainerMoveAssignmentTest { template static char test( typename _U::PropagateOnContainerMoveAssignment * = 0); template static int test(...); static constexpr bool value = (sizeof(test<_T>(0)) == 1); }; template::value> struct PropagateOnContainerMoveAssignmentBase { typedef octa::False Type; }; template struct PropagateOnContainerMoveAssignmentBase<_A, true> { typedef typename _A::PropagateOnContainerMoveAssignment Type; }; } /* namespace detail */ template using PropagateOnContainerMoveAssignment = typename octa::detail::PropagateOnContainerMoveAssignmentBase<_A>::Type; /* allocator propagate on container swap */ namespace detail { template struct PropagateOnContainerSwapTest { template static char test( typename _U::PropagateOnContainerSwap * = 0); template static int test(...); static constexpr bool value = (sizeof(test<_T>(0)) == 1); }; template::value> struct PropagateOnContainerSwapBase { typedef octa::False Type; }; template struct PropagateOnContainerSwapBase<_A, true> { typedef typename _A::PropagateOnContainerSwap Type; }; } /* namespace detail */ template using PropagateOnContainerSwap = typename octa::detail::PropagateOnContainerSwapBase<_A>::Type; /* allocator is always equal */ namespace detail { template struct IsAlwaysEqualTest { template static char test(typename _U::IsAlwaysEqual * = 0); template static int test(...); static constexpr bool value = (sizeof(test<_T>(0)) == 1); }; template::value> struct IsAlwaysEqualBase { typedef typename octa::IsEmpty<_A>::Type Type; }; template struct IsAlwaysEqualBase<_A, true> { typedef typename _A::IsAlwaysEqual Type; }; } /* namespace detail */ template using IsAlwaysEqual = typename octa::detail::IsAlwaysEqualBase<_A>::Type; /* allocator allocate */ template inline AllocatorPointer<_A> allocator_allocate(_A &a, AllocatorSize<_A> n) { return a.allocate(n); } namespace detail { template auto allocate_hint_test(_A &&a, _S &&sz, _CVP &&p) -> decltype(a.allocate(sz, p), octa::True()); template auto allocate_hint_test(const _A &, _S &&, _CVP &&) -> octa::False; template struct AllocateHintTest: octa::IntegralConstant(), octa::declval<_S>(), octa::declval<_CVP>())), octa::True >::value > {}; template inline AllocatorPointer<_A> allocate(_A &a, AllocatorSize<_A> n, AllocatorConstVoidPointer<_A> h, octa::True) { return a.allocate(n, h); } template inline AllocatorPointer<_A> allocate(_A &a, AllocatorSize<_A> n, AllocatorConstVoidPointer<_A>, octa::False) { return a.allocate(n); } } /* namespace detail */ template inline AllocatorPointer<_A> allocator_allocate(_A &a, AllocatorSize<_A> n, AllocatorConstVoidPointer<_A> h) { return octa::detail::allocate(a, n, h, octa::detail::AllocateHintTest< _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 */ namespace detail { template auto construct_test(_A &&a, _T *p, _Args &&...args) -> decltype(a.construct(p, octa::forward<_Args>(args)...), octa::True()); template auto construct_test(const _A &, _T *, _Args &&...) -> octa::False; template struct ConstructTest: octa::IntegralConstant(), octa::declval<_T>(), octa::declval<_Args>()...)), octa::True >::value > {}; template inline void construct(octa::True, _A &a, _T *p, _Args &&...args) { a.construct(p, octa::forward<_Args>(args)...); } template inline void construct(octa::False, _A &, _T *p, _Args &&...args) { ::new ((void *)p) _T(octa::forward<_Args>(args)...); } } /* namespace detail */ template inline void allocator_construct(_A &a, _T *p, _Args &&...args) { octa::detail::construct(octa::detail::ConstructTest< _A, _T *, _Args... >(), a, p, octa::forward<_Args>(args)...); } /* allocator destroy */ namespace detail { template auto destroy_test(_A &&a, _P &&p) -> decltype(a.destroy(p), octa::True()); template auto destroy_test(const _A &, _P &&) -> octa::False; template struct DestroyTest: octa::IntegralConstant(), octa::declval<_P>())), octa::True >::value > {}; template inline void destroy(octa::True, _A &a, _T *p) { a.destroy(p); } template inline void destroy(octa::False, _A &, _T *p) { p->~_T(); } } /* namespace detail */ template inline void allocator_destroy(_A &a, _T *p) { octa::detail::destroy(octa::detail::DestroyTest<_A, _T *>(), a, p); } /* allocator max size */ namespace detail { template auto alloc_max_size_test(_A &&a) -> decltype(a.max_size(), octa::True()); template auto alloc_max_size_test(const _A &) -> octa::False; template struct AllocMaxSizeTest: octa::IntegralConstant())), octa::True >::value > {}; template inline AllocatorSize<_A> alloc_max_size(octa::True, const _A &a) { return a.max_size(); } template inline AllocatorSize<_A> alloc_max_size(octa::False, const _A &) { return AllocatorSize<_A>(~0); } } /* namespace detail */ template inline AllocatorSize<_A> allocator_max_size(const _A &a) { return octa::detail::alloc_max_size(octa::detail::AllocMaxSizeTest< const _A >(), a); } /* allocator container copy */ namespace detail { template auto alloc_copy_test(_A &&a) -> decltype(a.container_copy(), octa::True()); template auto alloc_copy_test(const _A &) -> octa::False; template struct AllocCopyTest: octa::IntegralConstant())), octa::True >::value > {}; template inline AllocatorType<_A> alloc_container_copy(octa::True, const _A &a) { return a.container_copy(); } template inline AllocatorType<_A> alloc_container_copy(octa::False, const _A &a) { return a; } } /* namespace detail */ template inline AllocatorType<_A> allocator_container_copy(const _A &a) { return octa::detail::alloc_container_copy(octa::detail::AllocCopyTest< const _A >(), a); } } #endif