libostd/octa/memory.h

1115 lines
33 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>
2015-04-27 19:56:17 +02:00
#include "octa/new.h"
#include "octa/utility.h"
2015-04-27 19:56:17 +02:00
#include "octa/type_traits.h"
namespace octa {
2015-04-27 19:56:17 +02:00
/* address of */
2015-06-04 02:45:30 +02:00
template<typename _T> constexpr _T *address_of(_T &v) {
return reinterpret_cast<_T *>(&const_cast<char &>
2015-06-04 02:45:30 +02:00
(reinterpret_cast<const volatile char &>(v)));
}
2015-04-27 19:56:17 +02:00
/* pointer traits */
template<typename _T>
struct __OctaHasElement {
template<typename _U>
static int __test(...);
template<typename _U>
static char __test(typename _U::Element * = 0);
2015-04-27 19:56:17 +02:00
static constexpr bool value = (sizeof(__test<_T>(0)) == 1);
2015-04-27 19:56:17 +02:00
};
template<typename _T, bool = __OctaHasElement<_T>::value>
2015-04-27 19:56:17 +02:00
struct __OctaPtrTraitsElementType;
template<typename _T> struct __OctaPtrTraitsElementType<_T, true> {
typedef typename _T::Element Type;
2015-04-27 19:56:17 +02:00
};
template<template<typename, typename...> class _T, typename _U, typename ..._A>
struct __OctaPtrTraitsElementType<_T<_U, _A...>, true> {
typedef typename _T<_U, _A...>::Element Type;
2015-04-27 19:56:17 +02:00
};
template<template<typename, typename...> class _T, typename _U, typename ..._A>
struct __OctaPtrTraitsElementType<_T<_U, _A...>, false> {
typedef _U Type;
2015-04-27 19:56:17 +02:00
};
template<typename _T>
struct __OctaHasDifference {
template<typename _U>
static int __test(...);
template<typename _U>
static char __test(typename _U::Difference * = 0);
2015-04-27 19:56:17 +02:00
static constexpr bool value = (sizeof(__test<_T>(0)) == 1);
2015-04-27 19:56:17 +02:00
};
template<typename _T, bool = __OctaHasDifference<_T>::value>
struct __OctaPtrTraitsDifferenceType {
2015-05-04 00:50:09 +02:00
typedef ptrdiff_t Type;
2015-04-27 19:56:17 +02:00
};
template<typename _T> struct __OctaPtrTraitsDifferenceType<_T, true> {
typedef typename _T::Difference Type;
2015-04-27 19:56:17 +02:00
};
template<typename _T, typename _U>
2015-04-27 19:56:17 +02:00
struct __OctaHasRebind {
template<typename _V>
static int __test(...);
template<typename _V>
2015-06-03 20:47:36 +02:00
static char __test(typename _V::template Rebind<_U> * = 0);
2015-04-27 19:56:17 +02:00
static constexpr bool value = (sizeof(__test<_T>(0)) == 1);
2015-04-27 19:56:17 +02:00
};
template<typename _T, typename _U, bool = __OctaHasRebind<_T, _U>::value>
struct __OctaPtrTraitsRebindType {
2015-06-03 20:47:36 +02:00
typedef typename _T::template Rebind<_U> Type;
2015-04-27 19:56:17 +02:00
};
template<template<typename, typename...> class _T, typename _U,
typename ..._A, typename _V
2015-04-27 19:56:17 +02:00
>
struct __OctaPtrTraitsRebindType<_T<_U, _A...>, _V, true> {
2015-06-03 20:47:36 +02:00
typedef typename _T<_U, _A...>::template Rebind<_V> Type;
2015-04-27 19:56:17 +02:00
};
template<template<typename, typename...> class _T, typename _U,
typename ..._A, typename _V
2015-04-27 19:56:17 +02:00
>
struct __OctaPtrTraitsRebindType<_T<_U, _A...>, _V, false> {
typedef _T<_V, _A...> Type;
2015-04-27 19:56:17 +02:00
};
template<typename _T>
struct __OctaPtrTraitsPointer {
typedef _T Type;
};
2015-04-27 19:56:17 +02:00
template<typename _T>
struct __OctaPtrTraitsPointer<_T *> {
typedef _T *Type;
};
2015-04-27 19:56:17 +02:00
template<typename _T>
using Pointer = typename __OctaPtrTraitsPointer<_T>::Type;
2015-04-27 19:56:17 +02:00
template<typename _T>
struct __OctaPtrTraitsElement {
typedef typename __OctaPtrTraitsElementType<_T>::Type Type;
};
2015-04-27 19:56:17 +02:00
template<typename _T>
struct __OctaPtrTraitsElement<_T *> {
typedef _T Type;
2015-04-27 19:56:17 +02:00
};
template<typename _T>
using PointerElement = typename __OctaPtrTraitsElement<_T>::Type;
2015-04-27 19:56:17 +02:00
template<typename _T>
struct __OctaPtrTraitsDifference {
typedef typename __OctaPtrTraitsDifferenceType<_T>::Type Type;
};
template<typename _T>
struct __OctaPtrTraitsDifference<_T *> {
typedef ptrdiff_t Type;
};
2015-04-27 19:56:17 +02:00
template<typename _T>
using PointerDifference = typename __OctaPtrTraitsDifference<_T>::Type;
2015-04-27 19:56:17 +02:00
template<typename _T, typename _U>
struct __OctaPtrTraitsRebind {
using type = typename __OctaPtrTraitsRebindType<_T, _U>::Type;
};
2015-04-27 19:56:17 +02:00
template<typename _T, typename _U>
struct __OctaPtrTraitsRebind<_T *, _U> {
using type = _U *;
};
template<typename _T, typename _U>
using PointerRebind = typename __OctaPtrTraitsRebind<_T, _U>::Type;
struct __OctaPtrTraitsNat {};
template<typename _T>
struct __OctaPtrTraitsPointerTo {
static _T pointer_to(octa::Conditional<
octa::IsVoid<PointerElement<_T>>::value,
__OctaPtrTraitsNat, PointerElement<_T>
> &__r) {
return _T::pointer_to(__r);
}
};
template<typename _T>
struct __OctaPtrTraitsPointerTo<_T *> {
static _T pointer_to(octa::Conditional<
octa::IsVoid<_T>::value, __OctaPtrTraitsNat, _T
> &__r) {
return octa::address_of(__r);
2015-04-27 19:56:17 +02:00
}
};
template<typename _T>
static _T pointer_to(octa::Conditional<
octa::IsVoid<PointerElement<_T>>::value,
__OctaPtrTraitsNat, PointerElement<_T>
> &__r) {
return __OctaPtrTraitsPointerTo<_T>::pointer_to(__r);
}
2015-04-27 19:56:17 +02:00
/* default deleter */
template<typename _T>
2015-04-27 19:56:17 +02:00
struct DefaultDelete {
constexpr DefaultDelete() = default;
template<typename _U> DefaultDelete(const DefaultDelete<_U> &) {};
2015-04-27 19:56:17 +02:00
2015-06-04 02:45:30 +02:00
void operator()(_T *p) const {
delete p;
2015-04-27 19:56:17 +02:00
}
};
template<typename _T>
struct DefaultDelete<_T[]> {
2015-04-27 19:56:17 +02:00
constexpr DefaultDelete() = default;
template<typename _U> DefaultDelete(const DefaultDelete<_U[]> &) {};
2015-04-27 19:56:17 +02:00
2015-06-04 02:45:30 +02:00
void operator()(_T *p) const {
delete[] p;
2015-04-27 19:56:17 +02:00
}
template<typename _U> void operator()(_U *) const = delete;
2015-04-27 19:56:17 +02:00
};
/* box */
template<typename _T, typename _U, bool = octa::IsEmpty<_U>::value>
struct __OctaBoxPair;
template<typename _T, typename _U>
struct __OctaBoxPair<_T, _U, false> { /* non-empty deleter */
_T *__ptr;
private:
_U __del;
public:
template<typename _D>
__OctaBoxPair(_T *__ptr, _D &&__dltr): __ptr(__ptr),
__del(octa::forward<_D>(__dltr)) {}
_U &get_deleter() { return __del; }
const _U &get_deleter() const { return __del; }
void swap(__OctaBoxPair &__v) {
octa::swap(__ptr, __v.__ptr);
octa::swap(__del, __v.__del);
}
};
template<typename _T, typename _U>
struct __OctaBoxPair<_T, _U, true>: _U { /* empty deleter */
_T *__ptr;
template<typename _D>
__OctaBoxPair(_T *__ptr, _D &&__dltr):
_U(octa::forward<_D>(__dltr)), __ptr(__ptr) {}
_U &get_deleter() { return *this; }
const _U &get_deleter() const { return *this; }
void swap(__OctaBoxPair &__v) {
octa::swap(__ptr, __v.__ptr);
}
};
template<typename _T>
2015-04-27 19:56:17 +02:00
static int __octa_ptr_test(...);
template<typename _T>
static char __octa_ptr_test(typename _T::Pointer * = 0);
2015-04-27 19:56:17 +02:00
template<typename _T> struct __OctaHasPtr: octa::IntegralConstant<bool,
(sizeof(__octa_ptr_test<_T>(0)) == 1)
2015-04-27 19:56:17 +02:00
> {};
template<typename _T, typename _D, bool = __OctaHasPtr<_D>::value>
struct __OctaPointerBase {
typedef typename _D::Pointer Type;
2015-04-27 19:56:17 +02:00
};
template<typename _T, typename _D> struct __OctaPointerBase<_T, _D, false> {
typedef _T *Type;
2015-04-27 19:56:17 +02:00
};
template<typename _T, typename _D> struct __OctaPointer {
typedef typename __OctaPointerBase<_T, octa::RemoveReference<_D>>::Type Type;
2015-04-27 19:56:17 +02:00
};
template<typename _T, typename _D = DefaultDelete<_T>>
2015-04-27 19:56:17 +02:00
struct Box {
typedef _T Element;
typedef _D Deleter;
typedef typename __OctaPointer<_T, _D>::Type Pointer;
2015-04-27 19:56:17 +02:00
private:
struct __OctaNat { int __x; };
2015-04-27 19:56:17 +02:00
typedef RemoveReference<_D> &_D_ref;
typedef const RemoveReference<_D> &_D_cref;
2015-04-27 19:56:17 +02:00
public:
constexpr Box(): __stor(nullptr, _D()) {
static_assert(!octa::IsPointer<_D>::value,
2015-04-27 19:56:17 +02:00
"Box constructed with null fptr deleter");
}
constexpr Box(nullptr_t): __stor(nullptr, _D()) {
static_assert(!octa::IsPointer<_D>::value,
2015-04-27 19:56:17 +02:00
"Box constructed with null fptr deleter");
}
explicit Box(Pointer __p): __stor(__p, _D()) {
static_assert(!octa::IsPointer<_D>::value,
2015-04-27 19:56:17 +02:00
"Box constructed with null fptr deleter");
}
Box(Pointer __p, octa::Conditional<octa::IsReference<_D>::value,
_D, octa::AddLvalueReference<const _D>
> __d): __stor(__p, __d) {}
2015-04-27 19:56:17 +02:00
Box(Pointer __p, octa::RemoveReference<_D> &&__d):
__stor(__p, octa::move(__d)) {
static_assert(!octa::IsReference<_D>::value,
2015-04-27 19:56:17 +02:00
"rvalue deleter cannot be a ref");
}
Box(Box &&__u): __stor(__u.release(),
octa::forward<_D>(__u.get_deleter())) {}
2015-04-27 19:56:17 +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)
> = __OctaNat()): __stor(__u.release(), octa::forward<_DD>(__u.get_deleter())) {}
2015-04-27 19:56:17 +02:00
Box &operator=(Box &&__u) {
reset(__u.release());
__stor.get_deleter() = octa::forward<_D>(__u.get_deleter());
2015-04-27 19:56:17 +02:00
return *this;
}
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-04-27 19:56:17 +02:00
Box &
> operator=(Box<_TT, _DD> &&__u) {
reset(__u.release());
__stor.get_deleter() = octa::forward<_DD>(__u.get_deleter());
2015-04-27 19:56:17 +02:00
return *this;
}
Box &operator=(nullptr_t) {
2015-04-27 19:56:17 +02:00
reset();
return *this;
}
~Box() { reset(); }
octa::AddLvalueReference<_T> operator*() const { return *__stor.__ptr; }
Pointer operator->() const { return __stor.__ptr; }
2015-04-27 19:56:17 +02:00
explicit operator bool() const {
return __stor.__ptr != nullptr;
}
2015-04-27 19:56:17 +02:00
Pointer get() const { return __stor.__ptr; }
2015-04-27 19:56:17 +02:00
_D_ref get_deleter() { return __stor.get_deleter(); }
_D_cref get_deleter() const { return __stor.get_deleter(); }
2015-04-27 19:56:17 +02:00
Pointer release() {
Pointer __p = __stor.__ptr;
__stor.__ptr = nullptr;
return __p;
2015-04-27 19:56:17 +02:00
}
void reset(Pointer __p = nullptr) {
Pointer __tmp = __stor.__ptr;
__stor.__ptr = __p;
if (__tmp) __stor.get_deleter()(__tmp);
2015-04-27 19:56:17 +02:00
}
void swap(Box &__u) {
__stor.swap(__u.__stor);
2015-04-27 19:56:17 +02:00
}
private:
__OctaBoxPair<_T, _D> __stor;
2015-04-27 19:56:17 +02:00
};
template<typename _T, typename _U, bool = octa::IsSame<
octa::RemoveCv<PointerElement<_T>>,
octa::RemoveCv<PointerElement<_U>>
>::value> struct __OctaSameOrLessCvQualifiedBase: octa::IsConvertible<_T, _U> {};
2015-04-27 19:56:17 +02:00
template<typename _T, typename _U>
struct __OctaSameOrLessCvQualifiedBase<_T, _U, false>: octa::False {};
2015-04-27 19:56:17 +02:00
template<typename _T, typename _U, bool = octa::IsPointer<_T>::value
|| octa::IsSame<_T, _U>::value || __OctaHasElement<_T>::value
> struct __OctaSameOrLessCvQualified: __OctaSameOrLessCvQualifiedBase<_T, _U> {};
2015-04-27 19:56:17 +02:00
template<typename _T, typename _U>
struct __OctaSameOrLessCvQualified<_T, _U, false>: octa::False {};
2015-04-27 19:56:17 +02:00
template<typename _T, typename _D>
struct Box<_T[], _D> {
typedef _T Element;
typedef _D Deleter;
typedef typename __OctaPointer<_T, _D>::Type Pointer;
2015-04-27 19:56:17 +02:00
private:
struct __OctaNat { int __x; };
2015-04-27 19:56:17 +02:00
typedef RemoveReference<_D> &_D_ref;
typedef const RemoveReference<_D> &_D_cref;
2015-04-27 19:56:17 +02:00
public:
constexpr Box(): __stor(nullptr, _D()) {
static_assert(!octa::IsPointer<_D>::value,
2015-04-27 19:56:17 +02:00
"Box constructed with null fptr deleter");
}
constexpr Box(nullptr_t): __stor(nullptr, _D()) {
static_assert(!octa::IsPointer<_D>::value,
2015-04-27 19:56:17 +02:00
"Box constructed with null fptr deleter");
}
template<typename _U> explicit Box(_U __p, octa::EnableIf<
__OctaSameOrLessCvQualified<_U, Pointer>::value, __OctaNat
> = __OctaNat()): __stor(__p, _D()) {
static_assert(!octa::IsPointer<_D>::value,
2015-04-27 19:56:17 +02:00
"Box constructed with null fptr deleter");
}
template<typename _U> Box(_U __p, octa::Conditional<
octa::IsReference<_D>::value,
_D, AddLvalueReference<const _D>
> __d, octa::EnableIf<__OctaSameOrLessCvQualified<_U, Pointer>::value,
__OctaNat> = __OctaNat()): __stor(__p, __d) {}
2015-04-27 19:56:17 +02:00
Box(nullptr_t, octa::Conditional<octa::IsReference<_D>::value,
_D, AddLvalueReference<const _D>
> __d): __stor(nullptr, __d) {}
2015-04-27 19:56:17 +02:00
template<typename _U> Box(_U __p, octa::RemoveReference<_D> &&__d,
octa::EnableIf<
__OctaSameOrLessCvQualified<_U, Pointer>::value, __OctaNat
> = __OctaNat()): __stor(__p, octa::move(__d)) {
static_assert(!octa::IsReference<_D>::value,
2015-04-27 19:56:17 +02:00
"rvalue deleter cannot be a ref");
}
Box(nullptr_t, octa::RemoveReference<_D> &&__d):
__stor(nullptr, octa::move(__d)) {
static_assert(!octa::IsReference<_D>::value,
2015-04-27 19:56:17 +02:00
"rvalue deleter cannot be a ref");
}
Box(Box &&__u): __stor(__u.release(),
octa::forward<_D>(__u.get_deleter())) {}
2015-04-27 19:56:17 +02:00
template<typename _TT, typename _DD>
Box(Box<_TT, _DD> &&__u, EnableIf<IsArray<_TT>::value
&& __OctaSameOrLessCvQualified<typename Box<_TT, _DD>::Pointer,
Pointer>::value
&& octa::IsConvertible<_DD, _D>::value
&& (!octa::IsReference<_D>::value ||
octa::IsSame<_D, _DD>::value)> = __OctaNat()
): __stor(__u.release(), octa::forward<_DD>(__u.get_deleter())) {}
Box &operator=(Box &&__u) {
reset(__u.release());
__stor.get_deleter() = octa::forward<_D>(__u.get_deleter());
2015-04-27 19:56:17 +02:00
return *this;
}
template<typename _TT, typename _DD>
EnableIf<octa::IsArray<_TT>::value
&& __OctaSameOrLessCvQualified<typename Box<_TT, _DD>::Pointer,
Pointer>::value
&& IsAssignable<_D &, _DD &&>::value,
2015-04-27 19:56:17 +02:00
Box &
> operator=(Box<_TT, _DD> &&__u) {
reset(__u.release());
__stor.get_deleter() = octa::forward<_DD>(__u.get_deleter());
2015-04-27 19:56:17 +02:00
return *this;
}
Box &operator=(nullptr_t) {
2015-04-27 19:56:17 +02:00
reset();
return *this;
}
~Box() { reset(); }
octa::AddLvalueReference<_T> operator[](size_t __idx) const {
return __stor.__ptr[__idx];
2015-04-27 19:56:17 +02:00
}
explicit operator bool() const {
return __stor.__ptr != nullptr;
}
2015-04-27 19:56:17 +02:00
Pointer get() const { return __stor.__ptr; }
2015-04-27 19:56:17 +02:00
_D_ref get_deleter() { return __stor.get_deleter(); }
_D_cref get_deleter() const { return __stor.get_deleter(); }
2015-04-27 19:56:17 +02:00
Pointer release() {
Pointer __p = __stor.__ptr;
__stor.__ptr = nullptr;
return __p;
2015-04-27 19:56:17 +02:00
}
template<typename _U> EnableIf<
__OctaSameOrLessCvQualified<_U, Pointer>::value, void
> reset(_U __p) {
Pointer __tmp = __stor.__ptr;
__stor.__ptr = __p;
if (__tmp) __stor.get_deleter()(__tmp);
2015-04-27 19:56:17 +02:00
}
void reset(nullptr_t) {
Pointer __tmp = __stor.__ptr;
__stor.__ptr = nullptr;
if (__tmp) __stor.get_deleter()(__tmp);
2015-04-27 19:56:17 +02:00
}
void reset() {
2015-04-27 19:56:17 +02:00
reset(nullptr);
}
void swap(Box &__u) {
__stor.swap(__u.__stor);
2015-04-27 19:56:17 +02:00
}
private:
__OctaBoxPair<_T, _D> __stor;
2015-04-27 19:56:17 +02:00
};
2015-04-27 21:05:33 +02:00
template<typename _T> struct __OctaBoxIf {
typedef Box<_T> __OctaBox;
2015-04-27 21:05:33 +02:00
};
template<typename _T> struct __OctaBoxIf<_T[]> {
typedef Box<_T[]> __OctaBoxUnknownSize;
2015-04-27 21:05:33 +02:00
};
template<typename _T, size_t _N> struct __OctaBoxIf<_T[_N]> {
2015-04-27 21:05:33 +02:00
typedef void __OctaBoxKnownSize;
};
template<typename _T, typename ..._A>
typename __OctaBoxIf<_T>::__OctaBox make_box(_A &&...__args) {
return Box<_T>(new _T(octa::forward<_A>(__args)...));
2015-04-27 21:05:33 +02:00
}
template<typename _T>
typename __OctaBoxIf<_T>::__OctaBoxUnknownSize make_box(size_t __n) {
return Box<_T>(new octa::RemoveExtent<_T>[__n]());
2015-04-27 21:05:33 +02:00
}
template<typename _T, typename ..._A>
typename __OctaBoxIf<_T>::__OctaBoxKnownSize 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> {
typedef void Value;
typedef void *Pointer;
typedef const void *ConstPointer;
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _U> using Rebind = Allocator<_U>;
};
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<> struct Allocator<const void> {
typedef const void Value;
typedef const void *Pointer;
typedef const void *ConstPointer;
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _U> using Rebind = Allocator<_U>;
};
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _T> struct Allocator {
typedef size_t Size;
typedef ptrdiff_t Difference;
typedef _T Value;
typedef _T &Reference;
typedef const _T &ConstReference;
typedef _T *Pointer;
typedef const _T *ConstPointer;
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _U> using Rebind = Allocator<_U>;
2015-05-13 21:56:36 +02:00
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 02:56:04 +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 uchar[n * sizeof(_T)];
}
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
void deallocate(Pointer p, Size) { ::delete[] (uchar *) p; }
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _U, typename ..._A>
void construct(_U *p, _A &&...args) {
::new((void *)p) _U(octa::forward<_A>(args)...);
}
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
void destroy(Pointer p) { p->~_T(); }
};
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _T> struct Allocator<const _T> {
typedef size_t Size;
typedef ptrdiff_t Difference;
typedef const _T Value;
typedef const _T &Reference;
typedef const _T &ConstReference;
typedef const _T *Pointer;
typedef const _T *ConstPointer;
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _U> using Rebind = Allocator<_U>;
2015-05-13 21:56:36 +02:00
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 02:56:04 +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 uchar[n * sizeof(_T)];
}
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
void deallocate(Pointer p, Size) { ::delete[] (uchar *) p; }
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _U, typename ..._A>
void construct(_U *p, _A &&...args) {
::new((void *)p) _U(octa::forward<_A>(args)...);
}
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
void destroy(Pointer p) { p->~_T(); }
};
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _T, typename _U>
bool operator==(const Allocator<_T> &, const Allocator<_U> &) {
return true;
}
2015-05-13 21:56:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _T, typename _U>
bool operator!=(const Allocator<_T> &, const Allocator<_U> &) {
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-03 20:47:36 +02:00
template<typename _T>
2015-06-04 02:56:04 +02:00
struct ConstPtrTest {
template<typename _U> static char test(
typename _U::ConstPointer * = 0);
2015-06-04 02:56:04 +02:00
template<typename _U> static int test(...);
static constexpr bool value = (sizeof(test<_T>(0)) == 1);
2015-06-03 20:47:36 +02:00
};
template<typename _T, typename _P, typename _A,
2015-06-04 02:56:04 +02:00
bool = ConstPtrTest<_A>::value>
struct ConstPointer {
typedef typename _A::ConstPointer Type;
2015-06-03 20:47:36 +02:00
};
template<typename _T, typename _P, typename _A>
2015-06-04 02:56:04 +02:00
struct ConstPointer<_T, _P, _A, false> {
2015-06-03 20:47:36 +02:00
typedef PointerRebind<_P, const _T> Type;
};
template<typename _T>
2015-06-04 02:56:04 +02:00
struct VoidPtrTest {
template<typename _U> static char test(
typename _U::VoidPointer * = 0);
2015-06-04 02:56:04 +02:00
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 02:56:04 +02:00
template<typename _P, typename _A, bool = VoidPtrTest<_A>::value>
struct VoidPointer {
typedef typename _A::VoidPointer Type;
2015-06-03 20:47:36 +02:00
};
template<typename _P, typename _A>
2015-06-04 02:56:04 +02:00
struct VoidPointer<_P, _A, false> {
2015-06-03 20:47:36 +02:00
typedef PointerRebind<_P, void> Type;
};
template<typename _T>
2015-06-04 02:56:04 +02:00
struct ConstVoidPtrTest {
template<typename _U> static char test(
typename _U::ConstVoidPointer * = 0);
2015-06-04 02:56:04 +02:00
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 02:56:04 +02:00
template<typename _P, typename _A, bool = ConstVoidPtrTest<_A>::value>
struct ConstVoidPointer {
typedef typename _A::ConstVoidPointer Type;
2015-06-03 20:47:36 +02:00
};
template<typename _P, typename _A>
2015-06-04 02:56:04 +02:00
struct ConstVoidPointer<_P, _A, false> {
2015-06-03 20:47:36 +02:00
typedef PointerRebind<_P, const void> Type;
};
template<typename _T>
2015-06-04 02:56:04 +02:00
struct SizeTest {
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 02:56:04 +02:00
template<typename _A, typename _D, bool = SizeTest<_A>::value>
struct SizeBase {
2015-06-03 20:47:36 +02:00
typedef octa::MakeUnsigned<_D> Type;
};
template<typename _A, typename _D>
2015-06-04 02:56:04 +02:00
struct SizeBase<_A, _D, true> {
typedef typename _A::Size Type;
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 02:56:04 +02:00
template<typename _A>
using AllocatorType = _A;
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _A>
using AllocatorValue = typename AllocatorType<_A>::Value;
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _A>
using AllocatorPointer = typename __OctaPointer<
AllocatorValue<_A>, AllocatorType <_A>
>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _A>
using AllocatorConstPointer = typename octa::detail::ConstPointer<
AllocatorValue<_A>, AllocatorPointer<_A>, AllocatorType<_A>
>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _A>
using AllocatorVoidPointer = typename octa::detail::VoidPointer<
AllocatorPointer<_A>, AllocatorType<_A>
>::Type;
2015-06-03 20:47:36 +02:00
2015-06-04 02:56:04 +02:00
template<typename _A>
using AllocatorConstVoidPointer = typename octa::detail::ConstVoidPointer<
AllocatorPointer<_A>, AllocatorType<_A>
>::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-03 20:47:36 +02:00
template<typename _T>
2015-06-04 02:56:04 +02:00
struct DiffTest {
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 02:56:04 +02:00
template<typename _A, typename _P, bool = DiffTest<_A>::value>
struct AllocDifference {
2015-06-03 20:47:36 +02:00
typedef PointerDifference<_P> Type;
};
template<typename _A, typename _P>
2015-06-04 02:56:04 +02:00
struct AllocDifference<_A, _P, true> {
typedef typename _A::Difference Type;
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 02:56:04 +02:00
template<typename _A>
using AllocatorDifference = typename octa::detail::AllocDifference<
_A, AllocatorPointer<_A>
>::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 02:56:04 +02:00
template<typename _A>
using AllocatorSize = typename octa::detail::SizeBase<
_A, AllocatorDifference<_A>
>::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-03 20:47:36 +02:00
template<typename _T, typename _U, bool = __OctaHasRebind<_T, _U>::value>
2015-06-04 02:56:04 +02:00
struct AllocTraitsRebindType {
2015-06-03 20:47:36 +02:00
typedef typename _T::template Rebind<_U> Type;
};
template<template<typename, typename...> class _A, typename _T,
typename ..._Args, typename _U
>
2015-06-04 02:56:04 +02:00
struct AllocTraitsRebindType<_A<_T, _Args...>, _U, true> {
2015-06-03 20:47:36 +02:00
typedef typename _A<_T, _Args...>::template Rebind<_U> Type;
};
template<template<typename, typename...> class _A, typename _T,
typename ..._Args, typename _U
>
2015-06-04 02:56:04 +02:00
struct AllocTraitsRebindType<_A<_T, _Args...>, _U, false> {
2015-06-03 20:47:36 +02:00
typedef _A<_U, _Args...> Type;
};
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
template<typename _A, typename _T>
using AllocatorRebind = typename octa::detail::AllocTraitsRebindType<
AllocatorType<_A>, _T
>::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-03 20:47:36 +02:00
template<typename _T>
2015-06-04 02:56:04 +02:00
struct PropagateOnContainerCopyAssignmentTest {
template<typename _U> static char test(
2015-06-03 20:47:36 +02:00
typename _U::PropagateOnContainerCopyAssignment * = 0);
2015-06-04 02:56:04 +02:00
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 02:56:04 +02:00
template<typename _A, bool = PropagateOnContainerCopyAssignmentTest<
2015-06-03 20:47:36 +02:00
_A
2015-06-04 02:56:04 +02:00
>::value> struct PropagateOnContainerCopyAssignmentBase {
2015-06-03 20:47:36 +02:00
typedef octa::False Type;
};
template<typename _A>
2015-06-04 02:56:04 +02:00
struct PropagateOnContainerCopyAssignmentBase<_A, true> {
2015-06-03 20:47:36 +02:00
typedef typename _A::PropagateOnContainerCopyAssignment Type;
};
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
template<typename _A>
using PropagateOnContainerCopyAssignment
= 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-03 20:47:36 +02:00
template<typename _T>
2015-06-04 02:56:04 +02:00
struct PropagateOnContainerMoveAssignmentTest {
template<typename _U> static char test(
2015-06-03 20:47:36 +02:00
typename _U::PropagateOnContainerMoveAssignment * = 0);
2015-06-04 02:56:04 +02:00
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 02:56:04 +02:00
template<typename _A, bool = PropagateOnContainerMoveAssignmentTest<
2015-06-03 20:47:36 +02:00
_A
2015-06-04 02:56:04 +02:00
>::value> struct PropagateOnContainerMoveAssignmentBase {
2015-06-03 20:47:36 +02:00
typedef octa::False Type;
};
template<typename _A>
2015-06-04 02:56:04 +02:00
struct PropagateOnContainerMoveAssignmentBase<_A, true> {
2015-06-03 20:47:36 +02:00
typedef typename _A::PropagateOnContainerMoveAssignment Type;
};
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
template<typename _A>
using PropagateOnContainerMoveAssignment
= 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-03 20:47:36 +02:00
template<typename _T>
2015-06-04 02:56:04 +02:00
struct PropagateOnContainerSwapTest {
template<typename _U> static char test(
2015-06-03 20:47:36 +02:00
typename _U::PropagateOnContainerSwap * = 0);
2015-06-04 02:56:04 +02:00
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 02:56:04 +02:00
template<typename _A, bool = PropagateOnContainerSwapTest<_A>::value>
struct PropagateOnContainerSwapBase {
2015-06-03 20:47:36 +02:00
typedef octa::False Type;
};
template<typename _A>
2015-06-04 02:56:04 +02:00
struct PropagateOnContainerSwapBase<_A, true> {
2015-06-03 20:47:36 +02:00
typedef typename _A::PropagateOnContainerSwap Type;
};
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
template<typename _A>
using PropagateOnContainerSwap
= 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-03 20:47:36 +02:00
template<typename _T>
2015-06-04 02:56:04 +02:00
struct IsAlwaysEqualTest {
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 02:56:04 +02:00
template<typename _A, bool = IsAlwaysEqualTest<_A>::value>
struct IsAlwaysEqualBase {
2015-06-03 20:47:36 +02:00
typedef typename octa::IsEmpty<_A>::Type Type;
};
template<typename _A>
2015-06-04 02:56:04 +02:00
struct IsAlwaysEqualBase<_A, true> {
2015-06-03 20:47:36 +02:00
typedef typename _A::IsAlwaysEqual Type;
};
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
template<typename _A>
using IsAlwaysEqual = 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 02:45:30 +02:00
template<typename _A>
inline AllocatorPointer<_A>
allocator_allocate(_A &a, AllocatorSize<_A> n) {
return a.allocate(n);
}
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
template<typename _A, typename _S, typename _CVP>
2015-06-04 02:45:30 +02:00
auto allocate_hint_test(_A &&a, _S &&sz, _CVP &&p)
-> decltype(a.allocate(sz, p), octa::True());
2015-06-03 20:47:36 +02:00
template<typename _A, typename _S, typename _CVP>
2015-06-04 02:45:30 +02:00
auto allocate_hint_test(const _A &, _S &&, _CVP &&)
2015-06-03 20:47:36 +02:00
-> octa::False;
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 02:45:30 +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
> {};
template<typename _A>
2015-06-04 02:45:30 +02:00
inline AllocatorPointer<_A> allocate(_A &a, AllocatorSize<_A> n,
AllocatorConstVoidPointer<_A> h,
octa::True) {
return a.allocate(n, h);
2015-06-03 20:47:36 +02:00
}
template<typename _A>
2015-06-04 02:45:30 +02:00
inline AllocatorPointer<_A> allocate(_A &a, AllocatorSize<_A> n,
AllocatorConstVoidPointer<_A>,
octa::False) {
return a.allocate(n);
2015-06-03 20:47:36 +02:00
}
2015-06-04 02:45:30 +02:00
} /* namespace detail */
template<typename _A>
inline AllocatorPointer<_A>
allocator_allocate(_A &a, AllocatorSize<_A> n,
AllocatorConstVoidPointer<_A> h) {
return octa::detail::allocate(a, n, h,
octa::detail::AllocateHintTest<
2015-06-03 20:47:36 +02:00
_A, AllocatorSize<_A>, AllocatorConstVoidPointer<_A>
>());
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 02:45:30 +02:00
template<typename _A>
inline void allocator_deallocate(_A &a, AllocatorPointer<_A> p,
AllocatorSize<_A> n) {
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-03 20:47:36 +02:00
template<typename _A, typename _T, typename ..._Args>
2015-06-04 02:45:30 +02:00
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());
template<typename _A, typename _T, typename ..._Args>
2015-06-04 02:45:30 +02:00
auto construct_test(const _A &, _T *, _Args &&...)
2015-06-03 20:47:36 +02:00
-> octa::False;
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 02:45:30 +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
> {};
template<typename _A, typename _T, typename ..._Args>
2015-06-04 02:45:30 +02:00
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
}
template<typename _A, typename _T, typename ..._Args>
2015-06-04 02:45:30 +02:00
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 02:45:30 +02:00
template<typename _A, typename _T, typename ..._Args>
inline void allocator_construct(_A &a, _T *p, _Args &&...args) {
octa::detail::construct(octa::detail::ConstructTest<
_A, _T *, _Args...
>(), a, p, octa::forward<_Args>(args)...);
}
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-03 20:47:36 +02:00
template<typename _A, typename _P>
2015-06-04 02:45:30 +02:00
auto destroy_test(_A &&a, _P &&p) -> decltype(a.destroy(p), octa::True());
2015-06-03 20:47:36 +02:00
template<typename _A, typename _P>
2015-06-04 02:45:30 +02:00
auto destroy_test(const _A &, _P &&) -> octa::False;
2015-06-03 20:47:36 +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 02:45:30 +02:00
decltype(destroy_test(octa::declval<_A>(), octa::declval<_P>())),
2015-06-03 20:47:36 +02:00
octa::True
>::value
> {};
template<typename _A, typename _T>
2015-06-04 02:45:30 +02:00
inline void destroy(octa::True, _A &a, _T *p) {
a.destroy(p);
2015-06-03 20:47:36 +02:00
}
template<typename _A, typename _T>
2015-06-04 02:45:30 +02:00
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 02:45:30 +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-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-03 20:47:36 +02:00
template<typename _A>
2015-06-04 02:45:30 +02:00
auto alloc_max_size_test(_A &&a) -> decltype(a.max_size(), octa::True());
2015-06-03 20:47:36 +02:00
template<typename _A>
2015-06-04 02:45:30 +02:00
auto alloc_max_size_test(const _A &) -> octa::False;
2015-06-03 20:47:36 +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 02:45:30 +02:00
decltype(alloc_max_size_test(octa::declval<_A &>())),
2015-06-03 20:47:36 +02:00
octa::True
>::value
> {};
template<typename _A>
2015-06-04 02:45:30 +02:00
inline AllocatorSize<_A> alloc_max_size(octa::True, const _A &a) {
return a.max_size();
2015-06-03 20:47:36 +02:00
}
template<typename _A>
2015-06-04 02:45:30 +02:00
inline AllocatorSize<_A> alloc_max_size(octa::False, const _A &) {
2015-06-03 20:47:36 +02:00
return AllocatorSize<_A>(~0);
}
2015-06-04 02:45:30 +02:00
} /* namespace detail */
2015-06-03 20:47:36 +02:00
2015-06-04 02:45:30 +02:00
template<typename _A>
inline AllocatorSize<_A> allocator_max_size(const _A &a) {
return octa::detail::alloc_max_size(octa::detail::AllocMaxSizeTest<
const _A
>(), 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-03 20:47:36 +02:00
template<typename _A>
2015-06-04 02:45:30 +02:00
auto alloc_copy_test(_A &&a) -> decltype(a.container_copy(), octa::True());
2015-06-03 20:47:36 +02:00
template<typename _A>
2015-06-04 02:45:30 +02:00
auto alloc_copy_test(const _A &) -> octa::False;
2015-06-03 20:47:36 +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 02:45:30 +02:00
decltype(alloc_copy_test(octa::declval<_A &>())), octa::True
2015-06-03 20:47:36 +02:00
>::value
> {};
template<typename _A>
2015-06-04 02:45:30 +02:00
inline AllocatorType<_A> alloc_container_copy(octa::True, const _A &a) {
return a.container_copy();
2015-06-03 20:47:36 +02:00
}
template<typename _A>
2015-06-04 02:45:30 +02:00
inline AllocatorType<_A> alloc_container_copy(octa::False, const _A &a) {
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 02:45:30 +02:00
template<typename _A>
inline AllocatorType<_A> allocator_container_copy(const _A &a) {
return octa::detail::alloc_container_copy(octa::detail::AllocCopyTest<
const _A
>(), a);
}
}
#endif