/* 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 T *address_of(T &v) { 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::type::element * = 0); static constexpr bool value = (sizeof(__octa_test(0)) == 1); }; template::value> struct __OctaPtrTraitsElementType; template struct __OctaPtrTraitsElementType { typedef typename T::type::element type; }; template class T, typename U, typename ...A> struct __OctaPtrTraitsElementType, true> { typedef typename T::type::element 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::type::difference * = 0); static constexpr bool value = (sizeof(__octa_test(0)) == 1); }; template::value> struct __OctaPtrTraitsDifferenceType { typedef ptrdiff_t type; }; template struct __OctaPtrTraitsDifferenceType { typedef typename T::type::difference type; }; template struct __OctaHasRebind { template static int __octa_test(...); template static char __octa_test(typename V::type::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::type::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; typedef typename __OctaPtrTraitsDifferenceType::type difference; template using rebind = typename __OctaPtrTraitsRebind::type; private: struct __OctaNAT {}; public: static T pointer_to(Conditional::value, __OctaNAT, element > &r) { return T::pointer_to(r); } }; template struct PointerTraits { typedef T *pointer; typedef T element; typedef ptrdiff_t difference; template using rebind = U *; private: struct __OctaNAT {}; public: static T pointer_to(Conditional::value, __OctaNAT, element > &r) { return octa::address_of(r); } }; /* default deleter */ template struct DefaultDelete { constexpr DefaultDelete() = default; template DefaultDelete(const DefaultDelete &) {}; void operator()(T *p) const { delete p; } }; template struct DefaultDelete { constexpr DefaultDelete() = default; template DefaultDelete(const DefaultDelete &) {}; void operator()(T *p) const { delete[] p; } template void operator()(U *) const = delete; }; /* box */ template static int __octa_ptr_test(...); template static char __octa_ptr_test(typename T::type::pointer * = 0); template struct __OctaHasPtr: IntegralConstant(0)) == 1) > {}; template::value> struct __OctaPtrTypeBase { typedef typename D::type::pointer type; }; template struct __OctaPtrTypeBase { typedef T *type; }; template struct __OctaPtrType { typedef typename __OctaPtrTypeBase>::type type; }; template> struct Box { struct type { typedef T element; typedef D deleter; typedef typename __OctaPtrType::type pointer; }; private: struct __OctaNAT { int x; }; typedef RemoveReference &D_ref; typedef const RemoveReference &D_cref; public: constexpr Box(): p_ptr(nullptr), p_del() { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } constexpr Box(nullptr_t): p_ptr(nullptr), p_del() { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } explicit Box(typename type::pointer p): p_ptr(p), p_del() { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } Box(typename type::pointer p, Conditional::value, D, AddLvalueReference > d): p_ptr(p), p_del(d) {} Box(typename type::pointer p, RemoveReference &&d): p_ptr(p), p_del(move(d)) { static_assert(!IsReference::value, "rvalue deleter cannot be a ref"); } Box(Box &&u): p_ptr(u.release()), p_del(forward(u.get_deleter())) {} template Box(Box &&u, EnableIf::value && IsConvertible::type::pointer, typename type::pointer >::value && IsConvertible::value && (!IsReference::value || IsSame::value) > = __OctaNAT()): p_ptr(u.release()), p_del(forward
(u.get_deleter())) {} Box &operator=(Box &&u) { reset(u.release()); p_del = forward(u.get_deleter()); return *this; } template EnableIf::value && IsConvertible::type::pointer, typename type::pointer>::value && IsAssignable::value, Box & > operator=(Box &&u) { reset(u.release()); p_del = forward
(u.get_deleter()); return *this; } Box &operator=(nullptr_t) { reset(); return *this; } ~Box() { reset(); } AddLvalueReference operator*() const { return *p_ptr; } typename type::pointer operator->() const { return p_ptr; } explicit operator bool() const { return p_ptr != nullptr; } typename type::pointer get() const { return p_ptr; } D_ref get_deleter() { return p_del; } D_cref get_deleter() const { return p_del; } typename type::pointer release() { typename type::pointer p = p_ptr; p_ptr = nullptr; return p; } void reset(typename type::pointer p = nullptr) { typename type::pointer tmp = p_ptr; p_ptr = p; if (tmp) p_del(tmp); } void swap(Box &u) { 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>, RemoveCV::element> >::value> struct __OctaSameOrLessCVQualifiedBase: IsConvertible {}; template struct __OctaSameOrLessCVQualifiedBase: False {}; template::value || IsSame::value || __OctaHasElementType::value > struct __OctaSameOrLessCVQualified: __OctaSameOrLessCVQualifiedBase {}; template struct __OctaSameOrLessCVQualified: False {}; template struct Box { struct type { typedef T element; typedef D deleter; typedef typename __OctaPtrType::type pointer; }; private: struct __OctaNAT { int x; }; typedef RemoveReference &D_ref; typedef const RemoveReference &D_cref; public: constexpr Box(): p_ptr(nullptr), p_del() { static_assert(!IsPointer::value, "Box constructed with null fptr deleter"); } constexpr Box(nullptr_t): 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()): 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()): p_ptr(p), p_del(d) {} Box(nullptr_t, Conditional::value, D, AddLvalueReference > d): p_ptr(), p_del(d) {} template Box(U p, RemoveReference &&d, EnableIf<__OctaSameOrLessCVQualified::value, __OctaNAT > = __OctaNAT()): p_ptr(p), p_del(move(d)) { static_assert(!IsReference::value, "rvalue deleter cannot be a ref"); } Box(nullptr_t, RemoveReference &&d): p_ptr(), p_del(move(d)) { static_assert(!IsReference::value, "rvalue deleter cannot be a ref"); } Box(Box &&u): p_ptr(u.release()), p_del(forward(u.get_deleter())) {} template Box(Box &&u, EnableIf::value && __OctaSameOrLessCVQualified::type::pointer, typename type::pointer>::value && IsConvertible::value && (!IsReference::value || IsSame::value)> = __OctaNAT() ): p_ptr(u.release()), p_del(forward
(u.get_deleter())) {} Box &operator=(Box &&u) { reset(u.release()); p_del = forward(u.get_deleter()); return *this; } template EnableIf::value && __OctaSameOrLessCVQualified::type::pointer, typename type::pointer>::value && IsAssignable::value, Box & > operator=(Box &&u) { reset(u.release()); p_del = forward
(u.get_deleter()); return *this; } Box &operator=(nullptr_t) { reset(); return *this; } ~Box() { reset(); } AddLvalueReference operator[](size_t idx) const { return p_ptr[idx]; } explicit operator bool() const { return p_ptr != nullptr; } typename type::pointer get() const { return p_ptr; } D_ref get_deleter() { return p_del; } D_cref get_deleter() const { return p_del; } typename type::pointer release() { typename type::pointer p = p_ptr; p_ptr = nullptr; return p; } template EnableIf< __OctaSameOrLessCVQualified::value, void > reset(U p) { typename type::pointer tmp = p_ptr; p_ptr = p; if (tmp) p_del(tmp); } void reset(nullptr_t) { typename type::pointer tmp = p_ptr; p_ptr = nullptr; if (tmp) p_del(tmp); } void reset() { reset(nullptr); } void swap(Box &u) { octa::swap(p_ptr, u.p_ptr); octa::swap(p_del, u.p_del); } private: T *p_ptr; D p_del; }; } #endif