/* 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 "octa/new.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::element_type * = 0); static constexpr bool value = (sizeof(__octa_test(0)) == 1); }; template::value> struct __OctaPtrTraitsElementType; template struct __OctaPtrTraitsElementType { typedef typename T::element_type type; }; template class T, typename U, typename ...A> struct __OctaPtrTraitsElementType, true> { typedef typename T::element_type type; }; template class T, typename U, typename ...A> struct __OctaPtrTraitsElementType, false> { typedef U type; }; template struct __OctaHasDifferenceType { template static int __octa_test(...); template static char __octa_test(typename U::difference_type * = 0); static constexpr bool value = (sizeof(__octa_test(0)) == 1); }; template::value> struct __OctaPtrTraitsDifferenceType { typedef ptrdiff_t type; }; template struct __OctaPtrTraitsDifferenceType { typedef typename T::difference_type 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 __OctaPtrTraitsRebind { typedef typename T::template rebind type; }; template class T, typename U, typename ...A, typename V > struct __OctaPtrTraitsRebind, V, true> { typedef typename T::template rebind type; }; template class T, typename U, typename ...A, typename V > struct __OctaPtrTraitsRebind, V, false> { typedef T type; }; template struct PointerTraits { typedef T pointer; typedef typename __OctaPtrTraitsElementType ::type element_type; typedef typename __OctaPtrTraitsDifferenceType::type difference_type; template using rebind = typename __OctaPtrTraitsRebind::type; private: struct __OctaNat {}; public: static T pointer_to(Conditional::value, __OctaNat, element_type > &r) noexcept(noexcept(T::pointer_to(r))) { return T::pointer_to(r); } }; template struct PointerTraits { typedef T *pointer; typedef T element_type; typedef ptrdiff_t difference_type; template using rebind = U *; private: struct __OctaNat {}; public: static T pointer_to(Conditional::value, __OctaNat, element_type > &r) noexcept { return octa::address_of(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::pointer * = 0); template struct __OctaHasPtr: IntegralConstant(0)) == 1) > {}; template::value> struct __OctaPtrTypeBase { typedef typename D::pointer type; }; template struct __OctaPtrTypeBase { typedef T *type; }; template struct __OctaPtrType { typedef typename __OctaPtrTypeBase>::type type; }; template> struct Box { typedef T element_type; typedef D deleter_type; typedef typename __OctaPtrType::type pointer; 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(pointer p) noexcept: p_stor(p, D()) { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } Box(pointer p, Conditional::value, D, AddLvalueReference > d) noexcept: p_stor(p, d) {} Box(pointer 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::pointer, pointer>::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::pointer, pointer>::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; } pointer operator->() const noexcept { return p_stor.i_ptr; } explicit operator bool() const noexcept { return p_stor.i_ptr != nullptr; } pointer 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(); } pointer release() noexcept { pointer p = p_stor.i_ptr; p_stor.i_ptr = nullptr; return p; } void reset(pointer p = nullptr) noexcept { pointer 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::element_type>, RemoveCv::element_type> >::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 element_type; typedef D deleter_type; typedef typename __OctaPtrType::type pointer; 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::pointer, pointer>::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::pointer, pointer>::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; } pointer 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(); } pointer release() noexcept { pointer p = p_stor.i_ptr; p_stor.i_ptr = nullptr; return p; } template EnableIf< __OctaSameOrLessCvQualified::value, void > reset(U p) noexcept { pointer tmp = p_stor.i_ptr; p_stor.i_ptr = p; if (tmp) p_stor.get_deleter()(tmp); } void reset(nullptr_t) noexcept { pointer 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; } #endif