forked from OctaForge/libostd
initial Box and pointer traits impl
parent
b37921ee93
commit
990a7646da
432
octa/memory.h
432
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<typename T> T *address_of(T &v) {
|
||||
return reinterpret_cast<T *>(&const_cast<char &>
|
||||
(reinterpret_cast<const volatile char &>(v)));
|
||||
}
|
||||
|
||||
/* pointer traits */
|
||||
|
||||
template<typename T>
|
||||
struct __OctaHasElementType {
|
||||
template<typename U>
|
||||
static int __octa_test(...);
|
||||
template<typename U>
|
||||
static char __octa_test(typename U::type::element * = 0);
|
||||
|
||||
static constexpr bool value = (sizeof(__octa_test<T>(0)) == 1);
|
||||
};
|
||||
|
||||
template<typename T, bool = __OctaHasElementType<T>::value>
|
||||
struct __OctaPtrTraitsElementType;
|
||||
|
||||
template<typename T> struct __OctaPtrTraitsElementType<T, true> {
|
||||
typedef typename T::type::element type;
|
||||
};
|
||||
|
||||
template<template<typename, typename...> class T, typename U, typename ...A>
|
||||
struct __OctaPtrTraitsElementType<T<U, A...>, true> {
|
||||
typedef typename T<U, A...>::type::element type;
|
||||
};
|
||||
|
||||
template<template<typename, typename...> class T, typename U, typename ...A>
|
||||
struct __OctaPtrTraitsElementType<T<U, A...>, false> {
|
||||
typedef U type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct __OctaHasDifferenceType {
|
||||
template<typename U>
|
||||
static int __octa_test(...);
|
||||
template<typename U>
|
||||
static char __octa_test(typename U::type::difference * = 0);
|
||||
|
||||
static constexpr bool value = (sizeof(__octa_test<T>(0)) == 1);
|
||||
};
|
||||
|
||||
template<typename T, bool = __OctaHasDifferenceType<T>::value>
|
||||
struct __OctaPtrTraitsDifferenceType {
|
||||
typedef ptrdiff_t type;
|
||||
};
|
||||
|
||||
template<typename T> struct __OctaPtrTraitsDifferenceType<T, true> {
|
||||
typedef typename T::type::difference type;
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct __OctaHasRebind {
|
||||
template<typename V>
|
||||
static int __octa_test(...);
|
||||
template<typename V>
|
||||
static char __octa_test(typename V::type::template rebind<U> * = 0);
|
||||
|
||||
static constexpr bool value = (sizeof(__octa_test<T>(0)) == 1);
|
||||
};
|
||||
|
||||
template<typename T, typename U, bool = __OctaHasRebind<T, U>::value>
|
||||
struct __OctaPtrTraitsRebind {
|
||||
typedef typename T::template rebind<U> type;
|
||||
};
|
||||
|
||||
template<template<typename, typename...> class T, typename U,
|
||||
typename ...A, typename V
|
||||
>
|
||||
struct __OctaPtrTraitsRebind<T<U, A...>, V, true> {
|
||||
typedef typename T<U, A...>::type::template rebind<V> type;
|
||||
};
|
||||
|
||||
template<template<typename, typename...> class T, typename U,
|
||||
typename ...A, typename V
|
||||
>
|
||||
struct __OctaPtrTraitsRebind<T<U, A...>, V, false> {
|
||||
typedef T<V, A...> type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct PointerTraits {
|
||||
typedef T pointer;
|
||||
|
||||
typedef typename __OctaPtrTraitsElementType <T>::type element;
|
||||
typedef typename __OctaPtrTraitsDifferenceType<T>::type difference;
|
||||
|
||||
template<typename U>
|
||||
using rebind = typename __OctaPtrTraitsRebind<T, U>::type;
|
||||
|
||||
private:
|
||||
struct __OctaNAT {};
|
||||
|
||||
public:
|
||||
static T pointer_to(Conditional<IsVoid<element>::value,
|
||||
__OctaNAT, element
|
||||
> &r) {
|
||||
return T::pointer_to(r);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct PointerTraits<T *> {
|
||||
typedef T *pointer;
|
||||
typedef T element;
|
||||
|
||||
typedef ptrdiff_t difference;
|
||||
|
||||
template<typename U> using rebind = U *;
|
||||
|
||||
private:
|
||||
struct __OctaNAT {};
|
||||
|
||||
public:
|
||||
static T pointer_to(Conditional<IsVoid<element>::value,
|
||||
__OctaNAT, element
|
||||
> &r) {
|
||||
return octa::address_of(r);
|
||||
}
|
||||
};
|
||||
|
||||
/* default deleter */
|
||||
|
||||
template<typename T>
|
||||
struct DefaultDelete {
|
||||
constexpr DefaultDelete() = default;
|
||||
|
||||
template<typename U> DefaultDelete(const DefaultDelete<U> &) {};
|
||||
|
||||
void operator()(T *p) const {
|
||||
delete p;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DefaultDelete<T[]> {
|
||||
constexpr DefaultDelete() = default;
|
||||
|
||||
template<typename U> DefaultDelete(const DefaultDelete<U[]> &) {};
|
||||
|
||||
void operator()(T *p) const {
|
||||
delete[] p;
|
||||
}
|
||||
template<typename U> void operator()(U *) const = delete;
|
||||
};
|
||||
|
||||
/* box */
|
||||
|
||||
template<typename T>
|
||||
static int __octa_ptr_test(...);
|
||||
template<typename T>
|
||||
static char __octa_ptr_test(typename T::type::pointer * = 0);
|
||||
|
||||
template<typename T> struct __OctaHasPtr: IntegralConstant<bool,
|
||||
(sizeof(__octa_ptr_test<T>(0)) == 1)
|
||||
> {};
|
||||
|
||||
template<typename T, typename D, bool = __OctaHasPtr<D>::value>
|
||||
struct __OctaPtrTypeBase {
|
||||
typedef typename D::type::pointer type;
|
||||
};
|
||||
|
||||
template<typename T, typename D> struct __OctaPtrTypeBase<T, D, false> {
|
||||
typedef T *type;
|
||||
};
|
||||
|
||||
template<typename T, typename D> struct __OctaPtrType {
|
||||
typedef typename __OctaPtrTypeBase<T, RemoveReference<D>>::type type;
|
||||
};
|
||||
|
||||
template<typename T, typename D = DefaultDelete<T>>
|
||||
struct Box {
|
||||
struct type {
|
||||
typedef T element;
|
||||
typedef D deleter;
|
||||
typedef typename __OctaPtrType<T, D>::type pointer;
|
||||
};
|
||||
|
||||
private:
|
||||
struct __OctaNAT { int x; };
|
||||
|
||||
typedef RemoveReference<D> &D_ref;
|
||||
typedef const RemoveReference<D> &D_cref;
|
||||
|
||||
public:
|
||||
constexpr Box(): p_ptr(nullptr), p_del() {
|
||||
static_assert(!IsPointer<D>::value,
|
||||
"Box constructed with null fptr deleter");
|
||||
}
|
||||
constexpr Box(nullptr_t): p_ptr(nullptr), p_del() {
|
||||
static_assert(!IsPointer<D>::value,
|
||||
"Box constructed with null fptr deleter");
|
||||
}
|
||||
|
||||
explicit Box(typename type::pointer p): p_ptr(p), p_del() {
|
||||
static_assert(!IsPointer<D>::value,
|
||||
"Box constructed with null fptr deleter");
|
||||
}
|
||||
|
||||
Box(typename type::pointer p, Conditional<IsReference<D>::value,
|
||||
D, AddLvalueReference<const D>
|
||||
> d): p_ptr(p), p_del(d) {}
|
||||
|
||||
Box(typename type::pointer p, RemoveReference<D> &&d): p_ptr(p),
|
||||
p_del(move(d)) {
|
||||
static_assert(!IsReference<D>::value,
|
||||
"rvalue deleter cannot be a ref");
|
||||
}
|
||||
|
||||
Box(Box &&u): p_ptr(u.release()), p_del(forward<D>(u.get_deleter())) {}
|
||||
|
||||
template<typename TT, typename DD>
|
||||
Box(Box<TT, DD> &&u, EnableIf<!IsArray<TT>::value
|
||||
&& IsConvertible<typename Box<TT, DD>::type::pointer,
|
||||
typename type::pointer
|
||||
>::value
|
||||
&& IsConvertible<DD, D>::value
|
||||
&& (!IsReference<D>::value || IsSame<D, DD>::value)
|
||||
> = __OctaNAT()): p_ptr(u.release()),
|
||||
p_del(forward<DD>(u.get_deleter())) {}
|
||||
|
||||
Box &operator=(Box &&u) {
|
||||
reset(u.release());
|
||||
p_del = forward<D>(u.get_deleter());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename TT, typename DD>
|
||||
EnableIf<!IsArray<TT>::value
|
||||
&& IsConvertible<typename Box<TT, DD>::type::pointer,
|
||||
typename type::pointer>::value
|
||||
&& IsAssignable<D &, DD &&>::value,
|
||||
Box &
|
||||
> operator=(Box<TT, DD> &&u) {
|
||||
reset(u.release());
|
||||
p_del = forward<DD>(u.get_deleter());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Box &operator=(nullptr_t) {
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Box() { reset(); }
|
||||
|
||||
AddLvalueReference<T> 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<typename T, typename U, bool = IsSame<
|
||||
RemoveCV<typename PointerTraits<T>::element>,
|
||||
RemoveCV<typename PointerTraits<U>::element>
|
||||
>::value> struct __OctaSameOrLessCVQualifiedBase: IsConvertible<T, U> {};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct __OctaSameOrLessCVQualifiedBase<T, U, false>: False {};
|
||||
|
||||
template<typename T, typename U, bool = IsPointer<T>::value
|
||||
|| IsSame<T, U>::value || __OctaHasElementType<T>::value
|
||||
> struct __OctaSameOrLessCVQualified: __OctaSameOrLessCVQualifiedBase<T, U> {};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct __OctaSameOrLessCVQualified<T, U, false>: False {};
|
||||
|
||||
template<typename T, typename D>
|
||||
struct Box<T[], D> {
|
||||
struct type {
|
||||
typedef T element;
|
||||
typedef D deleter;
|
||||
typedef typename __OctaPtrType<T, D>::type pointer;
|
||||
};
|
||||
|
||||
private:
|
||||
struct __OctaNAT { int x; };
|
||||
|
||||
typedef RemoveReference<D> &D_ref;
|
||||
typedef const RemoveReference<D> &D_cref;
|
||||
|
||||
public:
|
||||
constexpr Box(): p_ptr(nullptr), p_del() {
|
||||
static_assert(!IsPointer<D>::value,
|
||||
"Box constructed with null fptr deleter");
|
||||
}
|
||||
constexpr Box(nullptr_t): p_ptr(nullptr), p_del() {
|
||||
static_assert(!IsPointer<D>::value,
|
||||
"Box constructed with null fptr deleter");
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
explicit Box(U p, EnableIf<__OctaSameOrLessCVQualified<U,
|
||||
typename type::pointer>::value, __OctaNAT
|
||||
> = __OctaNAT()): p_ptr(p), p_del() {
|
||||
static_assert(!IsPointer<D>::value,
|
||||
"Box constructed with null fptr deleter");
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
Box(U p, Conditional<IsReference<D>::value,
|
||||
D, AddLvalueReference<const D>
|
||||
> d, EnableIf<__OctaSameOrLessCVQualified<U,
|
||||
typename type::pointer>::value, __OctaNAT
|
||||
> = __OctaNAT()): p_ptr(p), p_del(d) {}
|
||||
|
||||
Box(nullptr_t, Conditional<IsReference<D>::value,
|
||||
D, AddLvalueReference<const D>
|
||||
> d): p_ptr(), p_del(d) {}
|
||||
|
||||
template<typename U>
|
||||
Box(U p, RemoveReference<D> &&d, EnableIf<__OctaSameOrLessCVQualified<U,
|
||||
typename type::pointer>::value, __OctaNAT
|
||||
> = __OctaNAT()): p_ptr(p), p_del(move(d)) {
|
||||
static_assert(!IsReference<D>::value,
|
||||
"rvalue deleter cannot be a ref");
|
||||
}
|
||||
|
||||
Box(nullptr_t, RemoveReference<D> &&d): p_ptr(), p_del(move(d)) {
|
||||
static_assert(!IsReference<D>::value,
|
||||
"rvalue deleter cannot be a ref");
|
||||
}
|
||||
|
||||
Box(Box &&u): p_ptr(u.release()), p_del(forward<D>(u.get_deleter())) {}
|
||||
|
||||
template<typename TT, typename DD>
|
||||
Box(Box<TT, DD> &&u, EnableIf<IsArray<TT>::value
|
||||
&& __OctaSameOrLessCVQualified<typename Box<TT, DD>::type::pointer,
|
||||
typename type::pointer>::value
|
||||
&& IsConvertible<DD, D>::value
|
||||
&& (!IsReference<D>::value || IsSame<D, DD>::value)> = __OctaNAT()
|
||||
): p_ptr(u.release()), p_del(forward<DD>(u.get_deleter())) {}
|
||||
|
||||
Box &operator=(Box &&u) {
|
||||
reset(u.release());
|
||||
p_del = forward<D>(u.get_deleter());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename TT, typename DD>
|
||||
EnableIf<IsArray<TT>::value
|
||||
&& __OctaSameOrLessCVQualified<typename Box<TT, DD>::type::pointer,
|
||||
typename type::pointer>::value
|
||||
&& IsAssignable<D &, DD &&>::value,
|
||||
Box &
|
||||
> operator=(Box<TT, DD> &&u) {
|
||||
reset(u.release());
|
||||
p_del = forward<DD>(u.get_deleter());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Box &operator=(nullptr_t) {
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Box() { reset(); }
|
||||
|
||||
AddLvalueReference<T> 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<typename U> EnableIf<
|
||||
__OctaSameOrLessCVQualified<U, typename type::pointer>::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
|
|
@ -1213,8 +1213,7 @@ namespace octa {
|
|||
|
||||
template<typename T> struct __OctaUnderlyingType<T, true> {
|
||||
typedef typename __OctaConditional<IsSigned<T>::value,
|
||||
typename MakeSigned<T>::type,
|
||||
typename MakeUnsigned<T>::type
|
||||
MakeSigned<T>, MakeUnsigned<T>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue