From 990a7646da2b1df25b86e980f7238d802af3d1a9 Mon Sep 17 00:00:00 2001 From: q66 Date: Mon, 27 Apr 2015 18:56:17 +0100 Subject: [PATCH] initial Box and pointer traits impl --- octa/memory.h | 432 +++++++++++++++++++++++++++++++++++++++++++++ octa/type_traits.h | 3 +- 2 files changed, 433 insertions(+), 2 deletions(-) diff --git a/octa/memory.h b/octa/memory.h index cff5727..f599d10 100644 --- a/octa/memory.h +++ b/octa/memory.h @@ -6,11 +6,443 @@ #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 \ No newline at end of file diff --git a/octa/type_traits.h b/octa/type_traits.h index ee12916..908429d 100644 --- a/octa/type_traits.h +++ b/octa/type_traits.h @@ -1213,8 +1213,7 @@ namespace octa { template struct __OctaUnderlyingType { typedef typename __OctaConditional::value, - typename MakeSigned::type, - typename MakeUnsigned::type + MakeSigned, MakeUnsigned >::type type; };