/* 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) noexcept { return reinterpret_cast(&const_cast (reinterpret_cast(v))); } /* pointer traits */ template struct __OctaHasElementType { template static int __octa_test(...); template static char __octa_test(typename U::ElementType * = 0); static constexpr bool value = (sizeof(__octa_test(0)) == 1); }; template::value> struct __OctaPtrTraitsElementType; template struct __OctaPtrTraitsElementType { typedef typename T::ElementType Type; }; template class T, typename U, typename ...A> struct __OctaPtrTraitsElementType, true> { typedef typename T::ElementType Type; }; template class T, typename U, typename ...A> struct __OctaPtrTraitsElementType, false> { typedef U Type; }; template struct __OctaHasDiffType { template static int __octa_test(...); template static char __octa_test(typename U::DiffType * = 0); static constexpr bool value = (sizeof(__octa_test(0)) == 1); }; template::value> struct __OctaPtrTraitsDiffType { typedef ptrdiff_t Type; }; template struct __OctaPtrTraitsDiffType { typedef typename T::DiffType Type; }; template struct __OctaHasRebind { template static int __octa_test(...); template static char __octa_test(typename V::template rebind * = 0); static constexpr bool value = (sizeof(__octa_test(0)) == 1); }; template::value> struct __OctaPtrTraitsRebindType { typedef typename T::template rebind Type; }; template class T, typename U, typename ...A, typename V > struct __OctaPtrTraitsRebindType, V, true> { typedef typename T::template rebind Type; }; template class T, typename U, typename ...A, typename V > struct __OctaPtrTraitsRebindType, V, false> { typedef T Type; }; template struct __OctaPtrTraitsPointer { typedef T Type; }; template struct __OctaPtrTraitsPointer { typedef T *Type; }; template using PtrType = typename __OctaPtrTraitsPointer::Type; template struct __OctaPtrTraitsElement { typedef typename __OctaPtrTraitsElementType::Type Type; }; template struct __OctaPtrTraitsElement { typedef T Type; }; template using PointerElement = typename __OctaPtrTraitsElement::Type; template struct __OctaPtrTraitsDifference { typedef typename __OctaPtrTraitsDiffType::Type Type; }; template struct __OctaPtrTraitsDifference { typedef ptrdiff_t DiffType; }; template using PointerDifference = typename __OctaPtrTraitsDifference::Type; template struct __OctaPtrTraitsRebind { using type = typename __OctaPtrTraitsRebindType::Type; }; template struct __OctaPtrTraitsRebind { using type = U *; }; template using PointerRebind = typename __OctaPtrTraitsRebind::Type; struct __OctaPtrTraitsNat {}; template struct __OctaPtrTraitsPointerTo { static T pointer_to(Conditional>::value, __OctaPtrTraitsNat, PointerElement > &r) noexcept(noexcept(T::pointer_to(r))) { return T::pointer_to(r); } }; template struct __OctaPtrTraitsPointerTo { static T pointer_to(Conditional::value, __OctaPtrTraitsNat, T> &r) noexcept { return octa::address_of(r); } }; template static T pointer_to(Conditional>::value, __OctaPtrTraitsNat, PointerElement > &r) noexcept(noexcept(__OctaPtrTraitsPointerTo::pointer_to(r))) { return __OctaPtrTraitsPointerTo::pointer_to(r); } /* default deleter */ template struct DefaultDelete { constexpr DefaultDelete() = default; template DefaultDelete(const DefaultDelete &) {}; void operator()(T *p) const noexcept { delete p; } }; template struct DefaultDelete { constexpr DefaultDelete() = default; template DefaultDelete(const DefaultDelete &) {}; void operator()(T *p) const noexcept { delete[] p; } template void operator()(U *) const = delete; }; /* box */ template::value> struct __OctaBoxPair; template struct __OctaBoxPair { /* non-empty deleter */ T *i_ptr; private: U p_del; public: template __OctaBoxPair(T *ptr, D &&dltr) noexcept: i_ptr(ptr), p_del(forward(dltr)) {} U &get_deleter() noexcept { return p_del; } const U &get_deleter() const noexcept { return p_del; } void swap(__OctaBoxPair &v) noexcept { octa::swap(i_ptr, v.i_ptr); octa::swap(p_del, v.p_del); } }; template struct __OctaBoxPair: U { /* empty deleter */ T *i_ptr; template __OctaBoxPair(T *ptr, D &&dltr) noexcept: U(forward(dltr)), i_ptr(ptr) {} U &get_deleter() noexcept { return *this; } const U &get_deleter() const noexcept { return *this; } void swap(__OctaBoxPair &v) noexcept { octa::swap(i_ptr, v.i_ptr); } }; template static int __octa_ptr_test(...); template static char __octa_ptr_test(typename T::PtrType * = 0); template struct __OctaHasPtr: IntegralConstant(0)) == 1) > {}; template::value> struct __OctaPtrTypeBase { typedef typename D::PtrType Type; }; template struct __OctaPtrTypeBase { typedef T *Type; }; template struct __OctaPtrType { typedef typename __OctaPtrTypeBase>::Type Type; }; template> struct Box { typedef T ElementType; typedef D DeleterType; typedef typename __OctaPtrType::Type PtrType; private: struct __OctaNat { int x; }; typedef RemoveReference &D_ref; typedef const RemoveReference &D_cref; public: constexpr Box() noexcept: p_stor(nullptr, D()) { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } constexpr Box(nullptr_t) noexcept: p_stor(nullptr, D()) { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } explicit Box(PtrType p) noexcept: p_stor(p, D()) { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } Box(PtrType p, Conditional::value, D, AddLvalueReference > d) noexcept: p_stor(p, d) {} Box(PtrType p, RemoveReference &&d) noexcept: p_stor(p, move(d)) { static_assert(!IsReference::value, "rvalue deleter cannot be a ref"); } Box(Box &&u) noexcept: p_stor(u.release(), forward(u.get_deleter())) {} template Box(Box &&u, EnableIf::value && IsConvertible::PtrType, PtrType>::value && IsConvertible::value && (!IsReference::value || IsSame::value) > = __OctaNat()) noexcept: p_stor(u.release(), forward
(u.get_deleter())) {} Box &operator=(Box &&u) noexcept { reset(u.release()); p_stor.get_deleter() = forward(u.get_deleter()); return *this; } template EnableIf::value && IsConvertible::PtrType, PtrType>::value && IsAssignable::value, Box & > operator=(Box &&u) noexcept { reset(u.release()); p_stor.get_deleter() = forward
(u.get_deleter()); return *this; } Box &operator=(nullptr_t) noexcept { reset(); return *this; } ~Box() { reset(); } AddLvalueReference operator*() const { return *p_stor.i_ptr; } PtrType operator->() const noexcept { return p_stor.i_ptr; } explicit operator bool() const noexcept { return p_stor.i_ptr != nullptr; } PtrType get() const noexcept { return p_stor.i_ptr; } D_ref get_deleter() noexcept { return p_stor.get_deleter(); } D_cref get_deleter() const noexcept { return p_stor.get_deleter(); } PtrType release() noexcept { PtrType p = p_stor.i_ptr; p_stor.i_ptr = nullptr; return p; } void reset(PtrType p = nullptr) noexcept { PtrType tmp = p_stor.i_ptr; p_stor.i_ptr = p; if (tmp) p_stor.get_deleter()(tmp); } void swap(Box &u) noexcept { p_stor.swap(u.p_stor); } private: __OctaBoxPair p_stor; }; template>, RemoveCv> >::value> struct __OctaSameOrLessCvQualifiedBase: IsConvertible {}; template struct __OctaSameOrLessCvQualifiedBase: False {}; template::value || IsSame::value || __OctaHasElementType::value > struct __OctaSameOrLessCvQualified: __OctaSameOrLessCvQualifiedBase {}; template struct __OctaSameOrLessCvQualified: False {}; template struct Box { typedef T ElementType; typedef D DeleterType; typedef typename __OctaPtrType::Type PtrType; private: struct __OctaNat { int x; }; typedef RemoveReference &D_ref; typedef const RemoveReference &D_cref; public: constexpr Box() noexcept: p_stor(nullptr, D()) { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } constexpr Box(nullptr_t) noexcept: p_stor(nullptr, D()) { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } template explicit Box(U p, EnableIf< __OctaSameOrLessCvQualified::value, __OctaNat > = __OctaNat()) noexcept: p_stor(p, D()) { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } template Box(U p, Conditional::value, D, AddLvalueReference > d, EnableIf<__OctaSameOrLessCvQualified::value, __OctaNat > = __OctaNat()) noexcept: p_stor(p, d) {} Box(nullptr_t, Conditional::value, D, AddLvalueReference > d) noexcept: p_stor(nullptr, d) {} template Box(U p, RemoveReference &&d, EnableIf< __OctaSameOrLessCvQualified::value, __OctaNat > = __OctaNat()) noexcept: p_stor(p, move(d)) { static_assert(!IsReference::value, "rvalue deleter cannot be a ref"); } Box(nullptr_t, RemoveReference &&d) noexcept: p_stor(nullptr, move(d)) { static_assert(!IsReference::value, "rvalue deleter cannot be a ref"); } Box(Box &&u) noexcept: p_stor(u.release(), forward(u.get_deleter())) {} template Box(Box &&u, EnableIf::value && __OctaSameOrLessCvQualified::PtrType, PtrType>::value && IsConvertible::value && (!IsReference::value || IsSame::value)> = __OctaNat() ) noexcept: p_stor(u.release(), forward
(u.get_deleter())) {} Box &operator=(Box &&u) noexcept { reset(u.release()); p_stor.get_deleter() = forward(u.get_deleter()); return *this; } template EnableIf::value && __OctaSameOrLessCvQualified::PtrType, PtrType>::value && IsAssignable::value, Box & > operator=(Box &&u) noexcept { reset(u.release()); p_stor.get_deleter() = forward
(u.get_deleter()); return *this; } Box &operator=(nullptr_t) noexcept { reset(); return *this; } ~Box() { reset(); } AddLvalueReference operator[](size_t idx) const { return p_stor.i_ptr[idx]; } explicit operator bool() const noexcept { return p_stor.i_ptr != nullptr; } PtrType get() const noexcept { return p_stor.i_ptr; } D_ref get_deleter() noexcept { return p_stor.get_deleter(); } D_cref get_deleter() const noexcept { return p_stor.get_deleter(); } PtrType release() noexcept { PtrType p = p_stor.i_ptr; p_stor.i_ptr = nullptr; return p; } template EnableIf< __OctaSameOrLessCvQualified::value, void > reset(U p) noexcept { PtrType tmp = p_stor.i_ptr; p_stor.i_ptr = p; if (tmp) p_stor.get_deleter()(tmp); } void reset(nullptr_t) noexcept { PtrType tmp = p_stor.i_ptr; p_stor.i_ptr = nullptr; if (tmp) p_stor.get_deleter()(tmp); } void reset() noexcept { reset(nullptr); } void swap(Box &u) noexcept { p_stor.swap(u.p_stor); } private: __OctaBoxPair p_stor; }; template struct __OctaBoxIf { typedef Box __OctaBox; }; template struct __OctaBoxIf { typedef Box __OctaBoxUnknownSize; }; template struct __OctaBoxIf { typedef void __OctaBoxKnownSize; }; template typename __OctaBoxIf::__OctaBox make_box(A &&...args) { return Box(new T(forward(args)...)); } template typename __OctaBoxIf::__OctaBoxUnknownSize make_box(size_t n) { return Box(new RemoveExtent[n]()); } template typename __OctaBoxIf::__OctaBoxKnownSize make_box(A &&...args) = delete; /* allocator */ template struct Allocator; template<> struct Allocator { typedef void ValType; typedef void *PtrType; typedef const void *ConstPtrType; template using Rebind = Allocator; }; template<> struct Allocator { typedef const void ValType; typedef const void *PtrType; typedef const void *ConstPtrType; template using Rebind = Allocator; }; template struct Allocator { typedef size_t SizeType; typedef ptrdiff_t DiffType; typedef T ValType; typedef T &RefType; typedef const T &ConstRefType; typedef T *PtrType; typedef const T *ConstPtrType; template using Rebind = Allocator; PtrType address(RefType v) const noexcept { return address_of(v); }; ConstPtrType address(ConstRefType v) const noexcept { return address_of(v); }; SizeType max_size() const noexcept { return SizeType(~0) / sizeof(T); } PtrType allocate(SizeType n, Allocator::ConstPtrType = nullptr) noexcept { return (PtrType) ::new uchar[n * sizeof(T)]; } void deallocate(PtrType p, SizeType) { ::delete[] (uchar *) p; } template void construct(U *p, A &&...args) { ::new((void *)p) U(forward(args)...); } void destroy(PtrType p) { p->~T(); } }; template struct Allocator { typedef size_t SizeType; typedef ptrdiff_t DiffType; typedef const T ValType; typedef const T &RefType; typedef const T &ConstRefType; typedef const T *PtrType; typedef const T *ConstPtrType; template using Rebind = Allocator; ConstPtrType address(ConstRefType v) const noexcept { return address_of(v); }; SizeType max_size() const noexcept { return SizeType(~0) / sizeof(T); } PtrType allocate(SizeType n, Allocator::ConstPtrType = nullptr) noexcept { return (PtrType) ::new uchar[n * sizeof(T)]; } void deallocate(PtrType p, SizeType) { ::delete[] (uchar *) p; } template void construct(U *p, A &&...args) { ::new((void *)p) U(forward(args)...); } void destroy(PtrType p) { p->~T(); } }; template bool operator==(const Allocator &, const Allocator &) noexcept { return true; } template bool operator!=(const Allocator &, const Allocator &) noexcept { return false; } } #endif