libostd/octa/memory.hh

1091 lines
30 KiB
C++
Raw Normal View History

/* Memory utilities for OctaSTD.
*
* This file is part of OctaSTD. See COPYING.md for futher information.
*/
#ifndef OCTA_MEMORY_H
#define OCTA_MEMORY_H
2015-05-13 21:56:36 +02:00
#include <stddef.h>
#include "octa/new.hh"
#include "octa/utility.hh"
#include "octa/type_traits.hh"
2015-04-27 19:56:17 +02:00
namespace octa {
2015-06-04 03:20:20 +02:00
/* address of */
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T> constexpr T *address_of(T &v) {
return reinterpret_cast<T *>(&const_cast<char &>
2015-06-04 03:20:20 +02:00
(reinterpret_cast<const volatile char &>(v)));
}
2015-04-27 19:56:17 +02:00
2015-06-04 03:20:20 +02:00
/* pointer traits */
2015-04-27 19:56:17 +02:00
2015-06-04 03:20:20 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 03:20:20 +02:00
struct HasElement {
2015-06-04 23:57:06 +02:00
template<typename U> static int test(...);
template<typename U> static char test(typename U::Element * = 0);
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
static constexpr bool value = (sizeof(test<T>(0)) == 1);
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T, bool = HasElement<T>::value>
2015-06-04 03:20:20 +02:00
struct PointerElementBase;
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T> struct PointerElementBase<T, true> {
2015-06-08 01:55:08 +02:00
using Type = typename T::Element;
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<template<typename, typename...> class T, typename U, typename ...A>
struct PointerElementBase<T<U, A...>, true> {
2015-06-08 01:55:08 +02:00
using Type = typename T<U, A...>::Element;
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<template<typename, typename...> class T, typename U, typename ...A>
struct PointerElementBase<T<U, A...>, false> {
2015-06-08 01:55:08 +02:00
using Type = U;
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 03:20:20 +02:00
struct PointerElementType {
2015-06-08 01:55:08 +02:00
using Type = typename PointerElementBase<T>::Type;
2015-06-04 03:20:20 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T>
struct PointerElementType<T *> {
2015-06-08 01:55:08 +02:00
using Type = T;
2015-06-04 03:20:20 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 03:20:20 +02:00
struct HasDifference {
2015-06-04 23:57:06 +02:00
template<typename U> static int test(...);
template<typename U> static char test(typename U::Difference * = 0);
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
static constexpr bool value = (sizeof(test<T>(0)) == 1);
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T, bool = HasDifference<T>::value>
2015-06-04 03:20:20 +02:00
struct PointerDifferenceBase {
using Type = octa::Ptrdiff;
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T> struct PointerDifferenceBase<T, true> {
2015-06-08 01:55:08 +02:00
using Type = typename T::Difference;
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 03:20:20 +02:00
struct PointerDifferenceType {
2015-06-08 01:55:08 +02:00
using Type = typename PointerDifferenceBase<T>::Type;
2015-06-04 03:20:20 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T>
struct PointerDifferenceType<T *> {
using Type = octa::Ptrdiff;
2015-06-04 03:20:20 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T, typename U>
2015-06-04 03:20:20 +02:00
struct HasRebind {
2015-06-04 23:57:06 +02:00
template<typename V> static int test(...);
template<typename V> static char test(
typename V::template Rebind<U> * = 0);
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
static constexpr bool value = (sizeof(test<T>(0)) == 1);
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T, typename U, bool = HasRebind<T, U>::value>
2015-06-04 03:20:20 +02:00
struct PointerRebindBase {
2015-06-08 01:55:08 +02:00
using Type = typename T::template Rebind<U>;
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<template<typename, typename...> class T, typename U,
typename ...A, typename V
2015-04-27 19:56:17 +02:00
>
2015-06-04 23:57:06 +02:00
struct PointerRebindBase<T<U, A...>, V, true> {
2015-06-08 01:55:08 +02:00
using Type = typename T<U, A...>::template Rebind<V>;
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<template<typename, typename...> class T, typename U,
typename ...A, typename V
2015-04-27 19:56:17 +02:00
>
2015-06-04 23:57:06 +02:00
struct PointerRebindBase<T<U, A...>, V, false> {
2015-06-08 01:55:08 +02:00
using Type = T<V, A...>;
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T, typename U>
2015-06-04 03:20:20 +02:00
struct PointerRebindType {
2015-06-04 23:57:06 +02:00
using type = typename PointerRebindBase<T, U>::Type;
};
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T, typename U>
struct PointerRebindType<T *, U> {
using type = U *;
};
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 03:20:20 +02:00
struct PointerPointer {
2015-06-08 01:55:08 +02:00
using Type = T;
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T>
struct PointerPointer<T *> {
2015-06-08 01:55:08 +02:00
using Type = T *;
};
2015-06-04 03:20:20 +02:00
} /*namespace detail */
2015-06-04 23:57:06 +02:00
template<typename T>
using Pointer = typename octa::detail::PointerPointer<T>::Type;
2015-06-04 23:57:06 +02:00
template<typename T>
using PointerElement = typename octa::detail::PointerElementType<T>::Type;
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T>
using PointerDifference = typename octa::detail::PointerDifferenceType<T>::Type;
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T, typename U>
using PointerRebind = typename octa::detail::PointerRebindType<T, U>::Type;
2015-06-04 03:20:20 +02:00
/* pointer to */
2015-06-04 03:20:20 +02:00
namespace detail {
struct PointerToNat {};
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 03:20:20 +02:00
struct PointerTo {
2015-06-04 23:57:06 +02:00
static T pointer_to(octa::Conditional<
octa::IsVoid<PointerElement<T>>::value,
PointerToNat, PointerElement<T>
2015-06-04 03:20:20 +02:00
> &r) {
2015-06-04 23:57:06 +02:00
return T::pointer_to(r);
}
};
2015-06-04 23:57:06 +02:00
template<typename T>
struct PointerTo<T *> {
static T pointer_to(octa::Conditional<
octa::IsVoid<T>::value, PointerToNat, T
2015-06-04 03:20:20 +02:00
> &r) {
return octa::address_of(r);
2015-04-27 19:56:17 +02:00
}
};
2015-06-04 03:20:20 +02:00
}
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T>
static T pointer_to(octa::Conditional<
octa::IsVoid<PointerElement<T>>::value,
octa::detail::PointerToNat, PointerElement<T>
2015-06-04 03:20:20 +02:00
> &r) {
2015-06-04 23:57:06 +02:00
return octa::detail::PointerTo<T>::pointer_to(r);
2015-06-04 03:20:20 +02:00
}
2015-06-04 03:20:20 +02:00
/* default deleter */
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 03:20:20 +02:00
struct DefaultDelete {
constexpr DefaultDelete() = default;
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename U> DefaultDelete(const DefaultDelete<U> &) {};
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
void operator()(T *p) const {
2015-06-04 03:20:20 +02:00
delete p;
}
};
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T>
struct DefaultDelete<T[]> {
2015-06-04 03:20:20 +02:00
constexpr DefaultDelete() = default;
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename U> DefaultDelete(const DefaultDelete<U[]> &) {};
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
void operator()(T *p) const {
2015-06-04 03:20:20 +02:00
delete[] p;
}
2015-06-04 23:57:06 +02:00
template<typename U> void operator()(U *) const = delete;
2015-06-04 03:20:20 +02:00
};
2015-04-27 19:56:17 +02:00
2015-06-04 03:20:20 +02:00
/* box */
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 03:09:07 +02:00
static int ptr_test(...);
2015-06-04 23:57:06 +02:00
template<typename T>
static char ptr_test(typename T::Pointer * = 0);
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T> struct HasPtr: octa::IntegralConstant<bool,
(sizeof(ptr_test<T>(0)) == 1)
2015-04-27 19:56:17 +02:00
> {};
2015-06-04 23:57:06 +02:00
template<typename T, typename D, bool = HasPtr<D>::value>
2015-06-04 03:09:07 +02:00
struct PointerBase {
2015-06-08 01:55:08 +02:00
using Type = typename D::Pointer;
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T, typename D> struct PointerBase<T, D, false> {
2015-06-08 01:55:08 +02:00
using Type = T *;
2015-04-27 19:56:17 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T, typename D> struct PointerType {
2015-06-08 01:55:08 +02:00
using Type = typename PointerBase<T, octa::RemoveReference<D>>::Type;
2015-04-27 19:56:17 +02:00
};
2015-06-04 03:09:07 +02:00
} /* namespace detail */
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T, typename D = DefaultDelete<T>>
2015-06-04 03:09:07 +02:00
struct Box {
2015-06-08 01:55:08 +02:00
using Element = T;
using Deleter = D;
using Pointer = typename octa::detail::PointerType<T, D>::Type;
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
private:
struct Nat { int x; };
2015-04-27 19:56:17 +02:00
2015-06-08 01:55:08 +02:00
using Dref = RemoveReference<D> &;
using Dcref = const RemoveReference<D> &;
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
public:
2015-06-04 23:57:06 +02:00
constexpr Box(): p_stor(nullptr, D()) {
static_assert(!octa::IsPointer<D>::value,
2015-06-04 03:09:07 +02:00
"Box constructed with null fptr deleter");
}
constexpr Box(octa::Nullptr): p_stor(nullptr, D()) {
2015-06-04 23:57:06 +02:00
static_assert(!octa::IsPointer<D>::value,
2015-06-04 03:09:07 +02:00
"Box constructed with null fptr deleter");
}
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
explicit Box(Pointer p): p_stor(p, D()) {
static_assert(!octa::IsPointer<D>::value,
2015-06-04 03:09:07 +02:00
"Box constructed with null fptr deleter");
}
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
Box(Pointer p, octa::Conditional<octa::IsReference<D>::value,
D, octa::AddLvalueReference<const D>
2015-06-04 03:09:07 +02:00
> d): p_stor(p, d) {}
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
Box(Pointer p, octa::RemoveReference<D> &&d):
2015-06-04 03:09:07 +02:00
p_stor(p, octa::move(d)) {
2015-06-04 23:57:06 +02:00
static_assert(!octa::IsReference<D>::value,
2015-06-04 03:09:07 +02:00
"rvalue deleter cannot be a ref");
}
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
Box(Box &&u): p_stor(u.release(), octa::forward<D>(u.get_deleter())) {}
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename TT, typename DD>
Box(Box<TT, DD> &&u, octa::EnableIf<!octa::IsArray<TT>::value
&& octa::IsConvertible<typename Box<TT, DD>::Pointer, Pointer>::value
&& octa::IsConvertible<DD, D>::value
&& (!octa::IsReference<D>::value || octa::IsSame<D, DD>::value)
> = Nat()): p_stor(u.release(), octa::forward<DD>(u.get_deleter())) {}
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
Box &operator=(Box &&u) {
reset(u.release());
p_stor.second() = octa::forward<D>(u.get_deleter());
2015-06-04 03:09:07 +02:00
return *this;
}
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename TT, typename DD>
EnableIf<!octa::IsArray<TT>::value
&& octa::IsConvertible<typename Box<TT, DD>::Pointer, Pointer>::value
&& octa::IsAssignable<D &, DD &&>::value,
2015-06-04 03:09:07 +02:00
Box &
2015-06-04 23:57:06 +02:00
> operator=(Box<TT, DD> &&u) {
2015-06-04 03:09:07 +02:00
reset(u.release());
p_stor.second() = octa::forward<DD>(u.get_deleter());
2015-06-04 03:09:07 +02:00
return *this;
}
2015-04-27 19:56:17 +02:00
Box &operator=(octa::Nullptr) {
2015-06-04 03:09:07 +02:00
reset();
return *this;
}
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
~Box() { reset(); }
2015-04-27 19:56:17 +02:00
octa::AddLvalueReference<T> operator*() const { return *p_stor.first(); }
Pointer operator->() const { return p_stor.first(); }
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
explicit operator bool() const {
return p_stor.first() != nullptr;
2015-06-04 03:09:07 +02:00
}
2015-04-27 19:56:17 +02:00
Pointer get() const { return p_stor.first(); }
2015-04-27 19:56:17 +02:00
Dref get_deleter() { return p_stor.second(); }
Dcref get_deleter() const { return p_stor.second(); }
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
Pointer release() {
Pointer p = p_stor.first();
p_stor.first() = nullptr;
2015-06-04 03:09:07 +02:00
return p;
}
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
void reset(Pointer p = nullptr) {
Pointer tmp = p_stor.first();
p_stor.first() = p;
if (tmp) p_stor.second()(tmp);
2015-06-04 03:09:07 +02:00
}
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
void swap(Box &u) {
p_stor.swap(u.p_stor);
}
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
private:
octa::detail::CompressedPair<T *, D> p_stor;
2015-06-04 03:09:07 +02:00
};
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename T, typename U, bool = octa::IsSame<
octa::RemoveCv<PointerElement<T>>,
octa::RemoveCv<PointerElement<U>>
>::value> struct SameOrLessCvQualifiedBase: octa::IsConvertible<T, U> {};
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T, typename U>
struct SameOrLessCvQualifiedBase<T, U, false>: octa::False {};
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T, typename U, bool = octa::IsPointer<T>::value
|| octa::IsSame<T, U>::value || octa::detail::HasElement<T>::value
> struct SameOrLessCvQualified: SameOrLessCvQualifiedBase<T, U> {};
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T, typename U>
struct SameOrLessCvQualified<T, U, false>: octa::False {};
2015-06-04 03:09:07 +02:00
} /* namespace detail */
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename T, typename D>
struct Box<T[], D> {
2015-06-08 01:55:08 +02:00
using Element = T;
using Deleter = D;
using Pointer = typename octa::detail::PointerType<T, D>::Type;
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
private:
struct Nat { int x; };
2015-04-27 19:56:17 +02:00
2015-06-08 01:55:08 +02:00
using Dref = RemoveReference<D> &;
using Dcref = const RemoveReference<D> &;
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
public:
2015-06-04 23:57:06 +02:00
constexpr Box(): p_stor(nullptr, D()) {
static_assert(!octa::IsPointer<D>::value,
2015-06-04 03:09:07 +02:00
"Box constructed with null fptr deleter");
}
constexpr Box(octa::Nullptr): p_stor(nullptr, D()) {
2015-06-04 23:57:06 +02:00
static_assert(!octa::IsPointer<D>::value,
2015-06-04 03:09:07 +02:00
"Box constructed with null fptr deleter");
}
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename U> explicit Box(U p, octa::EnableIf<
octa::detail::SameOrLessCvQualified<U, Pointer>::value, Nat
> = Nat()): p_stor(p, D()) {
static_assert(!octa::IsPointer<D>::value,
2015-06-04 03:09:07 +02:00
"Box constructed with null fptr deleter");
}
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename U> Box(U p, octa::Conditional<
octa::IsReference<D>::value,
D, AddLvalueReference<const D>
> d, octa::EnableIf<octa::detail::SameOrLessCvQualified<U, Pointer>::value,
2015-06-04 03:09:07 +02:00
Nat> = Nat()): p_stor(p, d) {}
Box(octa::Nullptr, octa::Conditional<octa::IsReference<D>::value,
2015-06-04 23:57:06 +02:00
D, AddLvalueReference<const D>
2015-06-04 03:09:07 +02:00
> d): p_stor(nullptr, d) {}
2015-06-04 23:57:06 +02:00
template<typename U> Box(U p, octa::RemoveReference<D> &&d,
2015-06-04 03:09:07 +02:00
octa::EnableIf<
2015-06-04 23:57:06 +02:00
octa::detail::SameOrLessCvQualified<U, Pointer>::value, Nat
2015-06-04 03:09:07 +02:00
> = Nat()): p_stor(p, octa::move(d)) {
2015-06-04 23:57:06 +02:00
static_assert(!octa::IsReference<D>::value,
2015-06-04 03:09:07 +02:00
"rvalue deleter cannot be a ref");
}
2015-04-27 19:56:17 +02:00
Box(octa::Nullptr, octa::RemoveReference<D> &&d):
2015-06-04 03:09:07 +02:00
p_stor(nullptr, octa::move(d)) {
2015-06-04 23:57:06 +02:00
static_assert(!octa::IsReference<D>::value,
2015-06-04 03:09:07 +02:00
"rvalue deleter cannot be a ref");
}
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
Box(Box &&u): p_stor(u.release(), octa::forward<D>(u.get_deleter())) {}
2015-06-04 03:09:07 +02:00
2015-06-04 23:57:06 +02:00
template<typename TT, typename DD>
Box(Box<TT, DD> &&u, EnableIf<IsArray<TT>::value
&& octa::detail::SameOrLessCvQualified<typename Box<TT, DD>::Pointer,
2015-06-04 03:09:07 +02:00
Pointer>::value
2015-06-04 23:57:06 +02:00
&& octa::IsConvertible<DD, D>::value
&& (!octa::IsReference<D>::value ||
octa::IsSame<D, DD>::value)> = Nat()
): p_stor(u.release(), octa::forward<DD>(u.get_deleter())) {}
2015-06-04 03:09:07 +02:00
Box &operator=(Box &&u) {
reset(u.release());
p_stor.second() = octa::forward<D>(u.get_deleter());
2015-06-04 03:09:07 +02:00
return *this;
}
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename TT, typename DD>
EnableIf<octa::IsArray<TT>::value
&& octa::detail::SameOrLessCvQualified<typename Box<TT, DD>::Pointer,
2015-06-04 03:09:07 +02:00
Pointer>::value
2015-06-04 23:57:06 +02:00
&& IsAssignable<D &, DD &&>::value,
2015-06-04 03:09:07 +02:00
Box &
2015-06-04 23:57:06 +02:00
> operator=(Box<TT, DD> &&u) {
2015-06-04 03:09:07 +02:00
reset(u.release());
p_stor.second() = octa::forward<DD>(u.get_deleter());
2015-06-04 03:09:07 +02:00
return *this;
}
2015-04-27 19:56:17 +02:00
Box &operator=(octa::Nullptr) {
2015-06-04 03:09:07 +02:00
reset();
return *this;
}
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
~Box() { reset(); }
2015-04-27 19:56:17 +02:00
octa::AddLvalueReference<T> operator[](octa::Size idx) const {
return p_stor.first()[idx];
2015-06-04 03:09:07 +02:00
}
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
explicit operator bool() const {
return p_stor.first() != nullptr;
2015-06-04 03:09:07 +02:00
}
2015-04-27 19:56:17 +02:00
Pointer get() const { return p_stor.first(); }
2015-04-27 19:56:17 +02:00
Dref get_deleter() { return p_stor.second(); }
Dcref get_deleter() const { return p_stor.second(); }
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
Pointer release() {
Pointer p = p_stor.first();
p_stor.first() = nullptr;
2015-06-04 03:09:07 +02:00
return p;
}
2015-04-27 19:56:17 +02:00
2015-06-04 23:57:06 +02:00
template<typename U> EnableIf<
octa::detail::SameOrLessCvQualified<U, Pointer>::value, void
> reset(U p) {
Pointer tmp = p_stor.first();
p_stor.first() = p;
if (tmp) p_stor.second()(tmp);
2015-06-04 03:09:07 +02:00
}
2015-04-27 19:56:17 +02:00
void reset(octa::Nullptr) {
Pointer tmp = p_stor.first();
p_stor.first() = nullptr;
if (tmp) p_stor.second()(tmp);
2015-06-04 03:09:07 +02:00
}
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
void reset() {
reset(nullptr);
}
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
void swap(Box &u) {
p_stor.swap(u.p_stor);
}
2015-04-27 19:56:17 +02:00
2015-06-04 03:09:07 +02:00
private:
octa::detail::CompressedPair<T *, D> p_stor;
2015-06-04 03:09:07 +02:00
};
2015-04-27 21:05:33 +02:00
2015-06-04 03:09:07 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename T> struct BoxIf {
2015-06-08 01:55:08 +02:00
using Box = octa::Box<T>;
2015-04-27 21:05:33 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T> struct BoxIf<T[]> {
2015-06-08 01:55:08 +02:00
using BoxUnknownSize = octa::Box<T[]>;
2015-04-27 21:05:33 +02:00
};
template<typename T, octa::Size N> struct BoxIf<T[N]> {
2015-06-08 01:55:08 +02:00
using BoxKnownSize = void;
2015-04-27 21:05:33 +02:00
};
2015-06-04 03:09:07 +02:00
}
2015-04-27 21:05:33 +02:00
2015-06-04 23:57:06 +02:00
template<typename T, typename ...A>
typename octa::detail::BoxIf<T>::Box make_box(A &&...args) {
return Box<T>(new T(octa::forward<A>(args)...));
2015-06-04 03:09:07 +02:00
}
2015-04-27 21:05:33 +02:00
2015-06-04 23:57:06 +02:00
template<typename T>
typename octa::detail::BoxIf<T>::BoxUnknownSize make_box(octa::Size n) {
2015-06-04 23:57:06 +02:00
return Box<T>(new octa::RemoveExtent<T>[n]());
2015-06-04 03:09:07 +02:00
}
2015-04-27 21:05:33 +02:00
2015-06-04 23:57:06 +02:00
template<typename T, typename ...A>
typename octa::detail::BoxIf<T>::BoxKnownSize make_box(A &&...args) = delete;
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
/* allocator */
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename> struct Allocator;
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<> struct Allocator<void> {
2015-06-08 01:55:08 +02:00
using Value = void;
using Pointer = void *;
using ConstPointer = const void *;
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename U> using Rebind = Allocator<U>;
2015-06-04 02:56:04 +02:00
};
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<> struct Allocator<const void> {
2015-06-08 01:55:08 +02:00
using Value = const void;
using Pointer = const void *;
using ConstPointer = const void *;
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename U> using Rebind = Allocator<U>;
2015-06-04 02:56:04 +02:00
};
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename T> struct Allocator {
using Size = octa::Size;
using Difference = octa::Ptrdiff;
2015-06-08 01:55:08 +02:00
using Value = T;
using Reference = T &;
using ConstReference = const T &;
using Pointer = T *;
using ConstPointer = const T *;
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename U> using Rebind = Allocator<U>;
2015-05-13 21:56:36 +02:00
2015-06-14 03:36:20 +02:00
Allocator() {}
template<typename U> Allocator(const Allocator<U> &) {}
2015-06-04 02:56:04 +02:00
Pointer address(Reference v) const {
return address_of(v);
};
ConstPointer address(ConstReference v) const {
return address_of(v);
};
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
Size max_size() const { return Size(~0) / sizeof(T); }
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
Pointer allocate(Size n, Allocator<void>::ConstPointer = nullptr) {
return (Pointer) ::new octa::uchar[n * sizeof(T)];
2015-06-04 02:56:04 +02:00
}
2015-05-13 21:56:36 +02:00
void deallocate(Pointer p, Size) { ::delete[] (octa::uchar *) p; }
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename U, typename ...A>
void construct(U *p, A &&...args) {
::new((void *)p) U(octa::forward<A>(args)...);
2015-06-04 02:56:04 +02:00
}
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
void destroy(Pointer p) { p->~T(); }
2015-06-04 02:56:04 +02:00
};
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename T> struct Allocator<const T> {
using Size = octa::Size;
using Difference = octa::Ptrdiff;
2015-06-08 01:55:08 +02:00
using Value = const T;
using Reference = const T &;
using ConstReference = const T &;
using Pointer = const T *;
using ConstPointer = const T *;
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename U> using Rebind = Allocator<U>;
2015-05-13 21:56:36 +02:00
2015-06-14 03:36:20 +02:00
Allocator() {}
template<typename U> Allocator(const Allocator<U> &) {}
2015-06-04 02:56:04 +02:00
ConstPointer address(ConstReference v) const {
return address_of(v);
};
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
Size max_size() const { return Size(~0) / sizeof(T); }
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
Pointer allocate(Size n, Allocator<void>::ConstPointer = nullptr) {
return (Pointer) ::new octa::uchar[n * sizeof(T)];
2015-06-04 02:56:04 +02:00
}
2015-05-13 21:56:36 +02:00
void deallocate(Pointer p, Size) { ::delete[] (octa::uchar *) p; }
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename U, typename ...A>
void construct(U *p, A &&...args) {
::new((void *)p) U(octa::forward<A>(args)...);
2015-06-04 02:56:04 +02:00
}
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
void destroy(Pointer p) { p->~T(); }
2015-06-04 02:56:04 +02:00
};
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename T, typename U>
bool operator==(const Allocator<T> &, const Allocator<U> &) {
2015-06-04 02:56:04 +02:00
return true;
}
2015-05-13 21:56:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename T, typename U>
bool operator!=(const Allocator<T> &, const Allocator<U> &) {
2015-06-04 02:56:04 +02:00
return false;
}
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
/* allocator traits - modeled after libc++ */
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 02:56:04 +02:00
struct ConstPtrTest {
2015-06-04 23:57:06 +02:00
template<typename U> static char test(
typename U::ConstPointer * = 0);
template<typename U> static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T, typename P, typename A,
bool = ConstPtrTest<A>::value>
2015-06-04 02:56:04 +02:00
struct ConstPointer {
2015-06-08 01:55:08 +02:00
using Type = typename A::ConstPointer;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T, typename P, typename A>
struct ConstPointer<T, P, A, false> {
2015-06-08 01:55:08 +02:00
using Type = PointerRebind<P, const T>;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 02:56:04 +02:00
struct VoidPtrTest {
2015-06-04 23:57:06 +02:00
template<typename U> static char test(
typename U::VoidPointer * = 0);
template<typename U> static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename P, typename A, bool = VoidPtrTest<A>::value>
2015-06-04 02:56:04 +02:00
struct VoidPointer {
2015-06-08 01:55:08 +02:00
using Type = typename A::VoidPointer;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename P, typename A>
struct VoidPointer<P, A, false> {
2015-06-08 01:55:08 +02:00
using Type = PointerRebind<P, void>;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 02:56:04 +02:00
struct ConstVoidPtrTest {
2015-06-04 23:57:06 +02:00
template<typename U> static char test(
typename U::ConstVoidPointer * = 0);
template<typename U> static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename P, typename A, bool = ConstVoidPtrTest<A>::value>
2015-06-04 02:56:04 +02:00
struct ConstVoidPointer {
2015-06-08 01:55:08 +02:00
using Type = typename A::ConstVoidPointer;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename P, typename A>
struct ConstVoidPointer<P, A, false> {
2015-06-08 01:55:08 +02:00
using Type = PointerRebind<P, const void>;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 02:56:04 +02:00
struct SizeTest {
2015-06-04 23:57:06 +02:00
template<typename U> static char test(typename U::Size * = 0);
template<typename U> static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename A, typename D, bool = SizeTest<A>::value>
2015-06-04 02:56:04 +02:00
struct SizeBase {
2015-06-08 01:55:08 +02:00
using Type = octa::MakeUnsigned<D>;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename A, typename D>
struct SizeBase<A, D, true> {
2015-06-08 01:55:08 +02:00
using Type = typename A::Size;
2015-06-03 20:47:36 +02:00
};
2015-06-04 02:56:04 +02:00
} /* namespace detail */
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
/* allocator type traits */
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
using AllocatorType = A;
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
using AllocatorValue = typename AllocatorType<A>::Value;
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
2015-06-04 03:09:07 +02:00
using AllocatorPointer = typename octa::detail::PointerType<
AllocatorValue<A>, AllocatorType<A>
2015-06-04 02:56:04 +02:00
>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
2015-06-04 02:56:04 +02:00
using AllocatorConstPointer = typename octa::detail::ConstPointer<
2015-06-04 23:57:06 +02:00
AllocatorValue<A>, AllocatorPointer<A>, AllocatorType<A>
2015-06-04 02:56:04 +02:00
>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
2015-06-04 02:56:04 +02:00
using AllocatorVoidPointer = typename octa::detail::VoidPointer<
2015-06-04 23:57:06 +02:00
AllocatorPointer<A>, AllocatorType<A>
2015-06-04 02:56:04 +02:00
>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
2015-06-04 02:56:04 +02:00
using AllocatorConstVoidPointer = typename octa::detail::ConstVoidPointer<
2015-06-04 23:57:06 +02:00
AllocatorPointer<A>, AllocatorType<A>
2015-06-04 02:56:04 +02:00
>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
/* allocator difference */
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 02:56:04 +02:00
struct DiffTest {
2015-06-04 23:57:06 +02:00
template<typename U> static char test(typename U::Difference * = 0);
template<typename U> static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename A, typename P, bool = DiffTest<A>::value>
2015-06-04 02:56:04 +02:00
struct AllocDifference {
2015-06-08 01:55:08 +02:00
using Type = PointerDifference<P>;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename A, typename P>
struct AllocDifference<A, P, true> {
2015-06-08 01:55:08 +02:00
using Type = typename A::Difference;
2015-06-03 20:47:36 +02:00
};
2015-06-04 02:56:04 +02:00
}
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
2015-06-04 02:56:04 +02:00
using AllocatorDifference = typename octa::detail::AllocDifference<
2015-06-04 23:57:06 +02:00
A, AllocatorPointer<A>
2015-06-04 02:56:04 +02:00
>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
/* allocator size */
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
2015-06-04 02:56:04 +02:00
using AllocatorSize = typename octa::detail::SizeBase<
2015-06-04 23:57:06 +02:00
A, AllocatorDifference<A>
2015-06-04 02:56:04 +02:00
>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
/* allocator rebind */
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename T, typename U, bool = octa::detail::HasRebind<T, U>::value>
2015-06-04 02:56:04 +02:00
struct AllocTraitsRebindType {
2015-06-08 01:55:08 +02:00
using Type = typename T::template Rebind<U>;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<template<typename, typename...> class A, typename T,
typename ...Args, typename U
2015-06-03 20:47:36 +02:00
>
2015-06-04 23:57:06 +02:00
struct AllocTraitsRebindType<A<T, Args...>, U, true> {
2015-06-08 01:55:08 +02:00
using Type = typename A<T, Args...>::template Rebind<U>;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<template<typename, typename...> class A, typename T,
typename ...Args, typename U
2015-06-03 20:47:36 +02:00
>
2015-06-04 23:57:06 +02:00
struct AllocTraitsRebindType<A<T, Args...>, U, false> {
2015-06-08 01:55:08 +02:00
using Type = A<U, Args...>;
2015-06-03 20:47:36 +02:00
};
2015-06-04 02:56:04 +02:00
} /* namespace detail */
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A, typename T>
2015-06-04 02:56:04 +02:00
using AllocatorRebind = typename octa::detail::AllocTraitsRebindType<
2015-06-04 23:57:06 +02:00
AllocatorType<A>, T
2015-06-04 02:56:04 +02:00
>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
/* allocator propagate on container copy assignment */
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 02:56:04 +02:00
struct PropagateOnContainerCopyAssignmentTest {
2015-06-04 23:57:06 +02:00
template<typename U> static char test(
typename U::PropagateOnContainerCopyAssignment * = 0);
template<typename U> static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename A, bool = PropagateOnContainerCopyAssignmentTest<
A
2015-06-04 02:56:04 +02:00
>::value> struct PropagateOnContainerCopyAssignmentBase {
2015-06-08 01:55:08 +02:00
using Type = octa::False;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename A>
struct PropagateOnContainerCopyAssignmentBase<A, true> {
2015-06-08 01:55:08 +02:00
using Type = typename A::PropagateOnContainerCopyAssignment;
2015-06-03 20:47:36 +02:00
};
2015-06-04 02:56:04 +02:00
} /* namespace detail */
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
2015-06-16 20:57:08 +02:00
using AllocatorPropagateOnContainerCopyAssignment
2015-06-04 23:57:06 +02:00
= typename octa::detail::PropagateOnContainerCopyAssignmentBase<A>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
/* allocator propagate on container move assignment */
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 02:56:04 +02:00
struct PropagateOnContainerMoveAssignmentTest {
2015-06-04 23:57:06 +02:00
template<typename U> static char test(
typename U::PropagateOnContainerMoveAssignment * = 0);
template<typename U> static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename A, bool = PropagateOnContainerMoveAssignmentTest<
A
2015-06-04 02:56:04 +02:00
>::value> struct PropagateOnContainerMoveAssignmentBase {
2015-06-08 01:55:08 +02:00
using Type = octa::False;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename A>
struct PropagateOnContainerMoveAssignmentBase<A, true> {
2015-06-08 01:55:08 +02:00
using Type = typename A::PropagateOnContainerMoveAssignment;
2015-06-03 20:47:36 +02:00
};
2015-06-04 02:56:04 +02:00
} /* namespace detail */
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
2015-06-16 20:57:08 +02:00
using AllocatorPropagateOnContainerMoveAssignment
2015-06-04 23:57:06 +02:00
= typename octa::detail::PropagateOnContainerMoveAssignmentBase<A>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
/* allocator propagate on container swap */
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 02:56:04 +02:00
struct PropagateOnContainerSwapTest {
2015-06-04 23:57:06 +02:00
template<typename U> static char test(
typename U::PropagateOnContainerSwap * = 0);
template<typename U> static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename A, bool = PropagateOnContainerSwapTest<A>::value>
2015-06-04 02:56:04 +02:00
struct PropagateOnContainerSwapBase {
2015-06-08 01:55:08 +02:00
using Type = octa::False;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename A>
struct PropagateOnContainerSwapBase<A, true> {
2015-06-08 01:55:08 +02:00
using Type = typename A::PropagateOnContainerSwap;
2015-06-03 20:47:36 +02:00
};
2015-06-04 02:56:04 +02:00
} /* namespace detail */
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
2015-06-16 20:57:08 +02:00
using AllocatorPropagateOnContainerSwap
2015-06-04 23:57:06 +02:00
= typename octa::detail::PropagateOnContainerSwapBase<A>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
/* allocator is always equal */
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 02:56:04 +02:00
struct IsAlwaysEqualTest {
2015-06-04 23:57:06 +02:00
template<typename U> static char test(typename U::IsAlwaysEqual * = 0);
template<typename U> static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename A, bool = IsAlwaysEqualTest<A>::value>
2015-06-04 02:56:04 +02:00
struct IsAlwaysEqualBase {
2015-06-08 01:55:08 +02:00
using Type = typename octa::IsEmpty<A>::Type;
2015-06-03 20:47:36 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename A>
struct IsAlwaysEqualBase<A, true> {
2015-06-08 01:55:08 +02:00
using Type = typename A::IsAlwaysEqual;
2015-06-03 20:47:36 +02:00
};
2015-06-04 02:56:04 +02:00
} /* namespace detail */
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
2015-06-16 20:57:08 +02:00
using AllocatorIsAlwaysEqual = typename octa::detail::IsAlwaysEqualBase<A>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 02:45:30 +02:00
/* allocator allocate */
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
inline AllocatorPointer<A>
allocator_allocate(A &a, AllocatorSize<A> n) {
2015-06-04 02:45:30 +02:00
return a.allocate(n);
}
2015-06-03 20:47:36 +02:00
2015-06-04 02:45:30 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename A, typename S, typename CVP>
auto allocate_hint_test(A &&a, S &&sz, CVP &&p)
2015-06-04 02:45:30 +02:00
-> decltype(a.allocate(sz, p), octa::True());
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A, typename S, typename CVP>
auto allocate_hint_test(const A &, S &&, CVP &&)
2015-06-03 20:47:36 +02:00
-> octa::False;
2015-06-04 23:57:06 +02:00
template<typename A, typename S, typename CVP>
2015-06-04 02:45:30 +02:00
struct AllocateHintTest: octa::IntegralConstant<bool,
2015-06-03 20:47:36 +02:00
octa::IsSame<
2015-06-04 23:57:06 +02:00
decltype(allocate_hint_test(octa::declval<A>(),
octa::declval<S>(),
octa::declval<CVP>())),
2015-06-03 20:47:36 +02:00
octa::True
>::value
> {};
2015-06-04 23:57:06 +02:00
template<typename A>
inline AllocatorPointer<A> allocate(A &a, AllocatorSize<A> n,
AllocatorConstVoidPointer<A> h,
2015-06-04 02:45:30 +02:00
octa::True) {
return a.allocate(n, h);
2015-06-03 20:47:36 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename A>
inline AllocatorPointer<A> allocate(A &a, AllocatorSize<A> n,
AllocatorConstVoidPointer<A>,
2015-06-04 02:45:30 +02:00
octa::False) {
return a.allocate(n);
2015-06-03 20:47:36 +02:00
}
2015-06-04 02:45:30 +02:00
} /* namespace detail */
2015-06-04 23:57:06 +02:00
template<typename A>
inline AllocatorPointer<A>
allocator_allocate(A &a, AllocatorSize<A> n,
AllocatorConstVoidPointer<A> h) {
2015-06-04 02:45:30 +02:00
return octa::detail::allocate(a, n, h,
octa::detail::AllocateHintTest<
2015-06-04 23:57:06 +02:00
A, AllocatorSize<A>, AllocatorConstVoidPointer<A>
2015-06-03 20:47:36 +02:00
>());
2015-06-04 02:45:30 +02:00
}
2015-06-03 20:47:36 +02:00
2015-06-04 02:45:30 +02:00
/* allocator deallocate */
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
inline void allocator_deallocate(A &a, AllocatorPointer<A> p,
AllocatorSize<A> n) {
2015-06-04 02:45:30 +02:00
a.deallocate(p, n);
}
2015-06-03 20:47:36 +02:00
2015-06-04 02:45:30 +02:00
/* allocator construct */
2015-06-03 20:47:36 +02:00
2015-06-04 02:45:30 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename A, typename T, typename ...Args>
auto construct_test(A &&a, T *p, Args &&...args)
-> decltype(a.construct(p, octa::forward<Args>(args)...),
2015-06-03 20:47:36 +02:00
octa::True());
2015-06-04 23:57:06 +02:00
template<typename A, typename T, typename ...Args>
auto construct_test(const A &, T *, Args &&...)
2015-06-03 20:47:36 +02:00
-> octa::False;
2015-06-04 23:57:06 +02:00
template<typename A, typename T, typename ...Args>
2015-06-04 02:45:30 +02:00
struct ConstructTest: octa::IntegralConstant<bool,
2015-06-03 20:47:36 +02:00
octa::IsSame<
2015-06-04 23:57:06 +02:00
decltype(construct_test(octa::declval<A>(),
octa::declval<T>(),
octa::declval<Args>()...)),
2015-06-03 20:47:36 +02:00
octa::True
>::value
> {};
2015-06-04 23:57:06 +02:00
template<typename A, typename T, typename ...Args>
inline void construct(octa::True, A &a, T *p, Args &&...args) {
a.construct(p, octa::forward<Args>(args)...);
2015-06-03 20:47:36 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename A, typename T, typename ...Args>
inline void construct(octa::False, A &, T *p, Args &&...args) {
::new ((void *)p) T(octa::forward<Args>(args)...);
2015-06-03 20:47:36 +02:00
}
2015-06-04 02:45:30 +02:00
} /* namespace detail */
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A, typename T, typename ...Args>
inline void allocator_construct(A &a, T *p, Args &&...args) {
2015-06-04 02:45:30 +02:00
octa::detail::construct(octa::detail::ConstructTest<
2015-06-04 23:57:06 +02:00
A, T *, Args...
>(), a, p, octa::forward<Args>(args)...);
2015-06-04 02:45:30 +02:00
}
2015-06-03 20:47:36 +02:00
2015-06-04 02:45:30 +02:00
/* allocator destroy */
2015-06-03 20:47:36 +02:00
2015-06-04 02:45:30 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename A, typename P>
auto destroy_test(A &&a, P &&p) -> decltype(a.destroy(p), octa::True());
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A, typename P>
auto destroy_test(const A &, P &&) -> octa::False;
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A, typename P>
2015-06-04 02:45:30 +02:00
struct DestroyTest: octa::IntegralConstant<bool,
2015-06-03 20:47:36 +02:00
octa::IsSame<
2015-06-04 23:57:06 +02:00
decltype(destroy_test(octa::declval<A>(), octa::declval<P>())),
2015-06-03 20:47:36 +02:00
octa::True
>::value
> {};
2015-06-04 23:57:06 +02:00
template<typename A, typename T>
inline void destroy(octa::True, A &a, T *p) {
2015-06-04 02:45:30 +02:00
a.destroy(p);
2015-06-03 20:47:36 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename A, typename T>
inline void destroy(octa::False, A &, T *p) {
p->~T();
2015-06-03 20:47:36 +02:00
}
2015-06-04 02:45:30 +02:00
} /* namespace detail */
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A, typename T>
inline void allocator_destroy(A &a, T *p) {
octa::detail::destroy(octa::detail::DestroyTest<A, T *>(), a, p);
2015-06-04 02:45:30 +02:00
}
2015-06-03 20:47:36 +02:00
2015-06-04 02:45:30 +02:00
/* allocator max size */
2015-06-03 20:47:36 +02:00
2015-06-04 02:45:30 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename A>
auto alloc_max_size_test(A &&a) -> decltype(a.max_size(), octa::True());
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
auto alloc_max_size_test(const A &) -> octa::False;
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
2015-06-04 02:45:30 +02:00
struct AllocMaxSizeTest: octa::IntegralConstant<bool,
2015-06-03 20:47:36 +02:00
octa::IsSame<
2015-06-04 23:57:06 +02:00
decltype(alloc_max_size_test(octa::declval<A &>())),
2015-06-03 20:47:36 +02:00
octa::True
>::value
> {};
2015-06-04 23:57:06 +02:00
template<typename A>
inline AllocatorSize<A> alloc_max_size(octa::True, const A &a) {
2015-06-04 02:45:30 +02:00
return a.max_size();
2015-06-03 20:47:36 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename A>
inline AllocatorSize<A> alloc_max_size(octa::False, const A &) {
return AllocatorSize<A>(~0);
2015-06-03 20:47:36 +02:00
}
2015-06-04 02:45:30 +02:00
} /* namespace detail */
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
inline AllocatorSize<A> allocator_max_size(const A &a) {
2015-06-04 02:45:30 +02:00
return octa::detail::alloc_max_size(octa::detail::AllocMaxSizeTest<
2015-06-04 23:57:06 +02:00
const A
2015-06-04 02:45:30 +02:00
>(), a);
}
2015-06-03 20:47:36 +02:00
2015-06-04 02:45:30 +02:00
/* allocator container copy */
2015-06-03 20:47:36 +02:00
2015-06-04 02:45:30 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename A>
auto alloc_copy_test(A &&a) -> decltype(a.container_copy(), octa::True());
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
auto alloc_copy_test(const A &) -> octa::False;
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
2015-06-04 02:45:30 +02:00
struct AllocCopyTest: octa::IntegralConstant<bool,
2015-06-03 20:47:36 +02:00
octa::IsSame<
2015-06-04 23:57:06 +02:00
decltype(alloc_copy_test(octa::declval<A &>())), octa::True
2015-06-03 20:47:36 +02:00
>::value
> {};
2015-06-04 23:57:06 +02:00
template<typename A>
inline AllocatorType<A> alloc_container_copy(octa::True, const A &a) {
2015-06-04 02:45:30 +02:00
return a.container_copy();
2015-06-03 20:47:36 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename A>
inline AllocatorType<A> alloc_container_copy(octa::False, const A &a) {
2015-06-04 02:45:30 +02:00
return a;
2015-06-03 20:47:36 +02:00
}
2015-06-04 02:45:30 +02:00
} /* namespace detail */
2015-06-03 20:47:36 +02:00
2015-06-04 23:57:06 +02:00
template<typename A>
inline AllocatorType<A> allocator_container_copy(const A &a) {
2015-06-04 02:45:30 +02:00
return octa::detail::alloc_container_copy(octa::detail::AllocCopyTest<
2015-06-04 23:57:06 +02:00
const A
2015-06-04 02:45:30 +02:00
>(), a);
}
2015-06-07 02:14:04 +02:00
struct AllocatorArg {};
constexpr AllocatorArg allocator_arg = AllocatorArg();
} /* namespace octa */
#endif