/* 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 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_ptr(nullptr), p_del() { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } constexpr Box(nullptr_t) noexcept: p_ptr(nullptr), p_del() { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } explicit Box(pointer p) noexcept: p_ptr(p), p_del() { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } Box(pointer p, Conditional::value, D, AddLvalueReference > d) noexcept: p_ptr(p), p_del(d) {} Box(pointer p, RemoveReference &&d) noexcept: p_ptr(p), p_del(move(d)) { static_assert(!IsReference::value, "rvalue deleter cannot be a ref"); } Box(Box &&u) noexcept: p_ptr(u.release()), p_del(forward(u.get_deleter())) {} template Box(Box &&u, EnableIf::value && IsConvertible::pointer, pointer>::value && IsConvertible::value && (!IsReference::value || IsSame::value) > = __OctaNat()) noexcept: p_ptr(u.release()), p_del(forward
(u.get_deleter())) {} Box &operator=(Box &&u) noexcept { reset(u.release()); p_del = forward(u.get_deleter()); return *this; } template EnableIf::value && IsConvertible::pointer, pointer>::value && IsAssignable::value, Box & > operator=(Box &&u) noexcept { reset(u.release()); p_del = forward
(u.get_deleter()); return *this; } Box &operator=(nullptr_t) noexcept { reset(); return *this; } ~Box() { reset(); } AddLvalueReference operator*() const { return *p_ptr; } pointer operator->() const noexcept { return p_ptr; } explicit operator bool() const noexcept { return p_ptr != nullptr; } pointer get() const noexcept { return p_ptr; } D_ref get_deleter() noexcept { return p_del; } D_cref get_deleter() const noexcept { return p_del; } pointer release() noexcept { pointer p = p_ptr; p_ptr = nullptr; return p; } void reset(pointer p = nullptr) noexcept { pointer tmp = p_ptr; p_ptr = p; if (tmp) p_del(tmp); } void swap(Box &u) noexcept { octa::swap(p_ptr, u.p_ptr); octa::swap(p_del, u.p_del); } private: /* TODO: optimize with pair (so that deleter doesn't take up memory) */ T *p_ptr; D p_del; }; 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_ptr(nullptr), p_del() { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } constexpr Box(nullptr_t) noexcept: p_ptr(nullptr), p_del() { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } template explicit Box(U p, EnableIf< __OctaSameOrLessCvQualified::value, __OctaNat > = __OctaNat()) noexcept: p_ptr(p), p_del() { 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_ptr(p), p_del(d) {} Box(nullptr_t, Conditional::value, D, AddLvalueReference > d) noexcept: p_ptr(), p_del(d) {} template Box(U p, RemoveReference &&d, EnableIf< __OctaSameOrLessCvQualified::value, __OctaNat > = __OctaNat()) noexcept: p_ptr(p), p_del(move(d)) { static_assert(!IsReference::value, "rvalue deleter cannot be a ref"); } Box(nullptr_t, RemoveReference &&d) noexcept: p_ptr(), p_del(move(d)) { static_assert(!IsReference::value, "rvalue deleter cannot be a ref"); } Box(Box &&u) noexcept: p_ptr(u.release()), p_del(forward(u.get_deleter())) {} template Box(Box &&u, EnableIf::value && __OctaSameOrLessCvQualified::pointer, pointer>::value && IsConvertible::value && (!IsReference::value || IsSame::value)> = __OctaNat() ) noexcept: p_ptr(u.release()), p_del(forward
(u.get_deleter())) {} Box &operator=(Box &&u) noexcept { reset(u.release()); p_del = forward(u.get_deleter()); return *this; } template EnableIf::value && __OctaSameOrLessCvQualified::pointer, pointer>::value && IsAssignable::value, Box & > operator=(Box &&u) noexcept { reset(u.release()); p_del = forward
(u.get_deleter()); return *this; } Box &operator=(nullptr_t) noexcept { reset(); return *this; } ~Box() { reset(); } AddLvalueReference operator[](size_t idx) const { return p_ptr[idx]; } explicit operator bool() const noexcept { return p_ptr != nullptr; } pointer get() const noexcept { return p_ptr; } D_ref get_deleter() noexcept { return p_del; } D_cref get_deleter() const noexcept { return p_del; } pointer release() noexcept { pointer p = p_ptr; p_ptr = nullptr; return p; } template EnableIf< __OctaSameOrLessCvQualified::value, void > reset(U p) noexcept { pointer tmp = p_ptr; p_ptr = p; if (tmp) p_del(tmp); } void reset(nullptr_t) noexcept { pointer tmp = p_ptr; p_ptr = nullptr; if (tmp) p_del(tmp); } void reset() noexcept { reset(nullptr); } void swap(Box &u) noexcept { octa::swap(p_ptr, u.p_ptr); octa::swap(p_del, u.p_del); } private: T *p_ptr; D p_del; }; 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