get rid of full namespace where unambiguous resolution is guaranteed

master
Daniel Kolesa 2015-07-05 23:59:36 +01:00
parent d2aba4d5b6
commit 1654ee84db
18 changed files with 1333 additions and 1418 deletions

View File

@ -42,25 +42,25 @@ bool is_partitioned(R range, P pred) {
namespace detail { namespace detail {
template<typename R, typename C> template<typename R, typename C>
void insort(R range, C compare) { void insort(R range, C compare) {
octa::RangeSize<R> rlen = range.size(); RangeSize<R> rlen = range.size();
for (octa::RangeSize<R> i = 1; i < rlen; ++i) { for (RangeSize<R> i = 1; i < rlen; ++i) {
octa::RangeSize<R> j = i; RangeSize<R> j = i;
octa::RangeValue<R> v(octa::move(range[i])); RangeValue<R> v(move(range[i]));
while (j > 0 && !compare(range[j - 1], v)) { while (j > 0 && !compare(range[j - 1], v)) {
range[j] = range[j - 1]; range[j] = range[j - 1];
--j; --j;
} }
range[j] = octa::move(v); range[j] = move(v);
} }
} }
template<typename R, typename C> template<typename R, typename C>
void hs_sift_down(R range, octa::RangeSize<R> s, void hs_sift_down(R range, RangeSize<R> s,
octa::RangeSize<R> e, C compare) { RangeSize<R> e, C compare) {
octa::RangeSize<R> r = s; RangeSize<R> r = s;
while ((r * 2 + 1) <= e) { while ((r * 2 + 1) <= e) {
octa::RangeSize<R> ch = r * 2 + 1; RangeSize<R> ch = r * 2 + 1;
octa::RangeSize<R> sw = r; RangeSize<R> sw = r;
if (compare(range[sw], range[ch])) if (compare(range[sw], range[ch]))
sw = ch; sw = ch;
if (((ch + 1) <= e) && compare(range[sw], range[ch + 1])) if (((ch + 1) <= e) && compare(range[sw], range[ch + 1]))
@ -74,32 +74,32 @@ namespace detail {
template<typename R, typename C> template<typename R, typename C>
void heapsort(R range, C compare) { void heapsort(R range, C compare) {
octa::RangeSize<R> len = range.size(); RangeSize<R> len = range.size();
octa::RangeSize<R> st = (len - 2) / 2; RangeSize<R> st = (len - 2) / 2;
for (;;) { for (;;) {
octa::detail::hs_sift_down(range, st, len - 1, compare); detail::hs_sift_down(range, st, len - 1, compare);
if (st-- == 0) break; if (st-- == 0) break;
} }
octa::RangeSize<R> e = len - 1; RangeSize<R> e = len - 1;
while (e > 0) { while (e > 0) {
octa::swap(range[e], range[0]); octa::swap(range[e], range[0]);
--e; --e;
octa::detail::hs_sift_down(range, 0, e, compare); detail::hs_sift_down(range, 0, e, compare);
} }
} }
template<typename R, typename C> template<typename R, typename C>
void introloop(R range, C compare, RangeSize<R> depth) { void introloop(R range, C compare, RangeSize<R> depth) {
if (range.size() <= 10) { if (range.size() <= 10) {
octa::detail::insort(range, compare); detail::insort(range, compare);
return; return;
} }
if (depth == 0) { if (depth == 0) {
octa::detail::heapsort(range, compare); detail::heapsort(range, compare);
return; return;
} }
octa::swap(range[range.size() / 2], range.back()); octa::swap(range[range.size() / 2], range.back());
octa::RangeSize<R> pi = 0; RangeSize<R> pi = 0;
R pr = range; R pr = range;
pr.pop_back(); pr.pop_back();
for (; !pr.empty(); pr.pop_front()) { for (; !pr.empty(); pr.pop_front()) {
@ -107,26 +107,26 @@ namespace detail {
octa::swap(pr.front(), range[pi++]); octa::swap(pr.front(), range[pi++]);
} }
octa::swap(range[pi], range.back()); octa::swap(range[pi], range.back());
octa::detail::introloop(range.slice(0, pi), compare, depth - 1); detail::introloop(range.slice(0, pi), compare, depth - 1);
octa::detail::introloop(range.slice(pi + 1, range.size()), compare, detail::introloop(range.slice(pi + 1, range.size()), compare,
depth - 1); depth - 1);
} }
template<typename R, typename C> template<typename R, typename C>
void introsort(R range, C compare) { void introsort(R range, C compare) {
octa::detail::introloop(range, compare, octa::RangeSize<R>(2 detail::introloop(range, compare, RangeSize<R>(2
* (log(range.size()) / log(2)))); * (log(range.size()) / log(2))));
} }
} /* namespace detail */ } /* namespace detail */
template<typename R, typename C> template<typename R, typename C>
void sort(R range, C compare) { void sort(R range, C compare) {
octa::detail::introsort(range, compare); detail::introsort(range, compare);
} }
template<typename R> template<typename R>
void sort(R range) { void sort(R range) {
sort(range, octa::Less<RangeValue<R>>()); sort(range, Less<RangeValue<R>>());
} }
/* min/max(_element) */ /* min/max(_element) */
@ -220,7 +220,7 @@ template<typename R, typename F>
F for_each(R range, F func) { F for_each(R range, F func) {
for (; !range.empty(); range.pop_front()) for (; !range.empty(); range.pop_front())
func(range.front()); func(range.front());
return octa::move(func); return move(func);
} }
template<typename R, typename P> template<typename R, typename P>
@ -333,7 +333,7 @@ R2 copy_if_not(R1 irange, R2 orange, P pred) {
template<typename R1, typename R2> template<typename R1, typename R2>
R2 move(R1 irange, R2 orange) { R2 move(R1 irange, R2 orange) {
for (; !irange.empty(); irange.pop_front()) for (; !irange.empty(); irange.pop_front())
orange.put(octa::move(irange.front())); orange.put(move(irange.front()));
return orange; return orange;
} }
@ -366,7 +366,7 @@ void generate(R range, F gen) {
} }
template<typename R1, typename R2> template<typename R1, typename R2>
octa::Pair<R1, R2> swap_ranges(R1 range1, R2 range2) { Pair<R1, R2> swap_ranges(R1 range1, R2 range2) {
while (!range1.empty() && !range2.empty()) { while (!range1.empty() && !range2.empty()) {
octa::swap(range1.front(), range2.front()); octa::swap(range1.front(), range2.front());
range1.pop_front(); range1.pop_front();
@ -411,11 +411,11 @@ T foldr(R range, T init, F func) {
template<typename T, typename F, typename R> template<typename T, typename F, typename R>
struct MapRange: InputRange< struct MapRange: InputRange<
MapRange<T, F, R>, octa::RangeCategory<T>, R, R, octa::RangeSize<T> MapRange<T, F, R>, RangeCategory<T>, R, R, RangeSize<T>
> { > {
private: private:
T p_range; T p_range;
octa::FunctionMakeDefaultConstructible<F> p_func; FunctionMakeDefaultConstructible<F> p_func;
public: public:
MapRange() = delete; MapRange() = delete;
@ -438,7 +438,7 @@ public:
} }
bool empty() const { return p_range.empty(); } bool empty() const { return p_range.empty(); }
octa::RangeSize<T> size() const { return p_range.size(); } RangeSize<T> size() const { return p_range.size(); }
bool equals_front(const MapRange &r) const { bool equals_front(const MapRange &r) const {
return p_range.equals_front(r.p_range); return p_range.equals_front(r.p_range);
@ -447,10 +447,10 @@ public:
return p_range.equals_front(r.p_range); return p_range.equals_front(r.p_range);
} }
octa::RangeDifference<T> distance_front(const MapRange &r) const { RangeDifference<T> distance_front(const MapRange &r) const {
return p_range.distance_front(r.p_range); return p_range.distance_front(r.p_range);
} }
octa::RangeDifference<T> distance_back(const MapRange &r) const { RangeDifference<T> distance_back(const MapRange &r) const {
return p_range.distance_back(r.p_range); return p_range.distance_back(r.p_range);
} }
@ -460,54 +460,51 @@ public:
bool push_front() { return p_range.pop_front(); } bool push_front() { return p_range.pop_front(); }
bool push_back() { return p_range.push_back(); } bool push_back() { return p_range.push_back(); }
octa::RangeSize<T> pop_front_n(octa::RangeSize<T> n) { RangeSize<T> pop_front_n(RangeSize<T> n) {
p_range.pop_front_n(n); p_range.pop_front_n(n);
} }
octa::RangeSize<T> pop_back_n(octa::RangeSize<T> n) { RangeSize<T> pop_back_n(RangeSize<T> n) {
p_range.pop_back_n(n); p_range.pop_back_n(n);
} }
octa::RangeSize<T> push_front_n(octa::RangeSize<T> n) { RangeSize<T> push_front_n(RangeSize<T> n) {
return p_range.push_front_n(n); return p_range.push_front_n(n);
} }
octa::RangeSize<T> push_back_n(octa::RangeSize<T> n) { RangeSize<T> push_back_n(RangeSize<T> n) {
return p_range.push_back_n(n); return p_range.push_back_n(n);
} }
R front() const { return p_func(p_range.front()); } R front() const { return p_func(p_range.front()); }
R back() const { return p_func(p_range.back()); } R back() const { return p_func(p_range.back()); }
R operator[](octa::RangeSize<T> idx) const { R operator[](RangeSize<T> idx) const {
return p_func(p_range[idx]); return p_func(p_range[idx]);
} }
MapRange slice(octa::RangeSize<T> start, MapRange slice(RangeSize<T> start, RangeSize<T> end) {
octa::RangeSize<T> end) {
return MapRange(p_range.slice(start, end), p_func); return MapRange(p_range.slice(start, end), p_func);
} }
}; };
namespace detail { namespace detail {
template<typename R, typename F> using MapReturnType template<typename R, typename F> using MapReturnType
= decltype(declval<F>()(octa::declval<octa::RangeReference<R>>())); = decltype(declval<F>()(declval<RangeReference<R>>()));
} }
template<typename R, typename F> template<typename R, typename F>
MapRange<R, F, octa::detail::MapReturnType<R, F>> map(R range, MapRange<R, F, detail::MapReturnType<R, F>> map(R range, F func) {
F func) { return MapRange<R, F, detail::MapReturnType<R, F>>(range,
return octa::MapRange<R, F, octa::detail::MapReturnType<R, F>>(range,
func); func);
} }
template<typename T, typename F> template<typename T, typename F>
struct FilterRange: InputRange< struct FilterRange: InputRange<
FilterRange<T, F>, octa::CommonType<octa::RangeCategory<T>, FilterRange<T, F>, CommonType<RangeCategory<T>, ForwardRangeTag>,
octa::ForwardRangeTag>, RangeValue<T>, RangeReference<T>, RangeSize<T>
octa::RangeValue<T>, octa::RangeReference<T>, octa::RangeSize<T>
> { > {
private: private:
T p_range; T p_range;
octa::FunctionMakeDefaultConstructible<F> p_pred; FunctionMakeDefaultConstructible<F> p_pred;
void advance_valid() { void advance_valid() {
while (!p_range.empty() && !p_pred(front())) p_range.pop_front(); while (!p_range.empty() && !p_pred(front())) p_range.pop_front();
@ -554,22 +551,19 @@ public:
return ret; return ret;
} }
octa::RangeReference<T> front() const { return p_range.front(); } RangeReference<T> front() const { return p_range.front(); }
}; };
namespace detail { namespace detail {
template<typename R, typename P> using FilterPred template<typename R, typename P> using FilterPred
= octa::EnableIf<IsSame< = EnableIf<IsSame<
decltype(octa::declval<P>()(octa::declval< decltype(declval<P>()(declval<RangeReference<R>>())), bool
octa::RangeReference<R>
>())),
bool
>::value, P>; >::value, P>;
} }
template<typename R, typename P> template<typename R, typename P>
FilterRange<R, octa::detail::FilterPred<R, P>> filter(R range, P pred) { FilterRange<R, detail::FilterPred<R, P>> filter(R range, P pred) {
return octa::FilterRange<R, P>(range, pred); return FilterRange<R, P>(range, pred);
} }
} /* namespace octa */ } /* namespace octa */

View File

@ -14,17 +14,17 @@
namespace octa { namespace octa {
template<typename T, octa::Size N> template<typename T, Size N>
struct Array { struct Array {
using Size = octa::Size; using Size = Size;
using Difference = octa::Ptrdiff; using Difference = Ptrdiff;
using Value = T; using Value = T;
using Reference = T &; using Reference = T &;
using ConstReference = const T &; using ConstReference = const T &;
using Pointer = T *; using Pointer = T *;
using ConstPointer = const T *; using ConstPointer = const T *;
using Range = octa::PointerRange<T>; using Range = PointerRange<T>;
using ConstRange = octa::PointerRange<const T>; using ConstRange = PointerRange<const T>;
T &operator[](Size i) { return p_buf[i]; } T &operator[](Size i) { return p_buf[i]; }
const T &operator[](Size i) const { return p_buf[i]; } const T &operator[](Size i) const { return p_buf[i]; }

View File

@ -115,7 +115,7 @@ namespace detail {
__atomic_signal_fence(to_gcc_order(ord)); __atomic_signal_fence(to_gcc_order(ord));
} }
static inline bool atomic_is_lock_free(octa::Size size) { static inline bool atomic_is_lock_free(Size size) {
/* return __atomic_is_lock_free(size, 0); cannot be used on some platforms */ /* return __atomic_is_lock_free(size, 0); cannot be used on some platforms */
return size <= sizeof(void *); return size <= sizeof(void *);
} }
@ -201,13 +201,13 @@ namespace detail {
} }
template<typename T> template<typename T>
struct SkipAmt { static constexpr octa::Size value = 1; }; struct SkipAmt { static constexpr Size value = 1; };
template<typename T> template<typename T>
struct SkipAmt<T *> { static constexpr octa::Size value = sizeof(T); }; struct SkipAmt<T *> { static constexpr Size value = sizeof(T); };
template<typename T> struct SkipAmt<T[]> {}; template<typename T> struct SkipAmt<T[]> {};
template<typename T, octa::Size N> struct SkipAmt<T[N]> {}; template<typename T, Size N> struct SkipAmt<T[N]> {};
template<typename T, typename U> template<typename T, typename U>
static inline T atomic_fetch_add(volatile AtomicBase<T> *a, static inline T atomic_fetch_add(volatile AtomicBase<T> *a,
@ -288,8 +288,7 @@ template <typename T> inline T kill_dependency(T v) {
} }
namespace detail { namespace detail {
template<typename T, bool = octa::IsIntegral<T>::value && template<typename T, bool = IsIntegral<T>::value && !IsSame<T, bool>::value>
!octa::IsSame<T, bool>::value>
struct Atomic { struct Atomic {
mutable AtomicBase<T> p_a; mutable AtomicBase<T> p_a;
@ -451,8 +450,8 @@ namespace detail {
} }
template<typename T> template<typename T>
struct Atomic: octa::detail::Atomic<T> { struct Atomic: detail::Atomic<T> {
using Base = octa::detail::Atomic<T>; using Base = detail::Atomic<T>;
Atomic() = default; Atomic() = default;
@ -468,8 +467,8 @@ struct Atomic: octa::detail::Atomic<T> {
}; };
template<typename T> template<typename T>
struct Atomic<T *>: octa::detail::Atomic<T *> { struct Atomic<T *>: detail::Atomic<T *> {
using Base = octa::detail::Atomic<T *>; using Base = detail::Atomic<T *>;
Atomic() = default; Atomic() = default;
@ -483,22 +482,22 @@ struct Atomic<T *>: octa::detail::Atomic<T *> {
Base::store(v); return v; Base::store(v); return v;
} }
T *fetch_add(octa::Ptrdiff op, MemoryOrder ord = MemoryOrder::seq_cst) T *fetch_add(Ptrdiff op, MemoryOrder ord = MemoryOrder::seq_cst)
volatile { volatile {
return octa::detail::atomic_fetch_add(&this->p_a, op, ord); return detail::atomic_fetch_add(&this->p_a, op, ord);
} }
T *fetch_add(octa::Ptrdiff op, MemoryOrder ord = MemoryOrder::seq_cst) { T *fetch_add(Ptrdiff op, MemoryOrder ord = MemoryOrder::seq_cst) {
return octa::detail::atomic_fetch_add(&this->p_a, op, ord); return detail::atomic_fetch_add(&this->p_a, op, ord);
} }
T *fetch_sub(octa::Ptrdiff op, MemoryOrder ord = MemoryOrder::seq_cst) T *fetch_sub(Ptrdiff op, MemoryOrder ord = MemoryOrder::seq_cst)
volatile { volatile {
return octa::detail::atomic_fetch_sub(&this->p_a, op, ord); return detail::atomic_fetch_sub(&this->p_a, op, ord);
} }
T *fetch_sub(octa::Ptrdiff op, MemoryOrder ord = MemoryOrder::seq_cst) { T *fetch_sub(Ptrdiff op, MemoryOrder ord = MemoryOrder::seq_cst) {
return octa::detail::atomic_fetch_sub(&this->p_a, op, ord); return detail::atomic_fetch_sub(&this->p_a, op, ord);
} }
@ -511,10 +510,10 @@ struct Atomic<T *>: octa::detail::Atomic<T *> {
T *operator--( ) volatile { return fetch_sub(1) - 1; } T *operator--( ) volatile { return fetch_sub(1) - 1; }
T *operator--( ) { return fetch_sub(1) - 1; } T *operator--( ) { return fetch_sub(1) - 1; }
T *operator+=(octa::Ptrdiff op) volatile { return fetch_add(op) + op; } T *operator+=(Ptrdiff op) volatile { return fetch_add(op) + op; }
T *operator+=(octa::Ptrdiff op) { return fetch_add(op) + op; } T *operator+=(Ptrdiff op) { return fetch_add(op) + op; }
T *operator-=(octa::Ptrdiff op) volatile { return fetch_sub(op) - op; } T *operator-=(Ptrdiff op) volatile { return fetch_sub(op) - op; }
T *operator-=(octa::Ptrdiff op) { return fetch_sub(op) - op; } T *operator-=(Ptrdiff op) { return fetch_sub(op) - op; }
}; };
template<typename T> template<typename T>
@ -529,12 +528,12 @@ inline bool atomic_is_lock_free(const Atomic<T> *a) {
template<typename T> template<typename T>
inline void atomic_init(volatile Atomic<T> *a, T v) { inline void atomic_init(volatile Atomic<T> *a, T v) {
octa::detail::atomic_init(&a->p_a, v); detail::atomic_init(&a->p_a, v);
} }
template<typename T> template<typename T>
inline void atomic_init(Atomic<T> *a, T v) { inline void atomic_init(Atomic<T> *a, T v) {
octa::detail::atomic_init(&a->p_a, v); detail::atomic_init(&a->p_a, v);
} }
template <typename T> template <typename T>
@ -657,196 +656,176 @@ inline bool atomic_compare_exchange_strong_explicit(Atomic<T> *a, T *e,
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_add(volatile Atomic<T> *a, T op) { atomic_fetch_add(volatile Atomic<T> *a, T op) {
return a->fetch_add(op); return a->fetch_add(op);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_add(Atomic<T> *a, T op) { atomic_fetch_add(Atomic<T> *a, T op) {
return a->fetch_add(op); return a->fetch_add(op);
} }
template <typename T> template <typename T>
inline T *atomic_fetch_add(volatile Atomic<T *> *a, octa::Ptrdiff op) { inline T *atomic_fetch_add(volatile Atomic<T *> *a, Ptrdiff op) {
return a->fetch_add(op); return a->fetch_add(op);
} }
template <typename T> template <typename T>
inline T *atomic_fetch_add(Atomic<T *> *a, octa::Ptrdiff op) { inline T *atomic_fetch_add(Atomic<T *> *a, Ptrdiff op) {
return a->fetch_add(op); return a->fetch_add(op);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_add_explicit(volatile Atomic<T> *a, T op, atomic_fetch_add_explicit(volatile Atomic<T> *a, T op,
MemoryOrder ord) { MemoryOrder ord) {
return a->fetch_add(op, ord); return a->fetch_add(op, ord);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_add_explicit(Atomic<T> *a, T op, MemoryOrder ord) { atomic_fetch_add_explicit(Atomic<T> *a, T op, MemoryOrder ord) {
return a->fetch_add(op, ord); return a->fetch_add(op, ord);
} }
template <typename T> template <typename T>
inline T *atomic_fetch_add_explicit(volatile Atomic<T *> *a, inline T *atomic_fetch_add_explicit(volatile Atomic<T *> *a,
octa::Ptrdiff op, MemoryOrder ord) { Ptrdiff op, MemoryOrder ord) {
return a->fetch_add(op, ord); return a->fetch_add(op, ord);
} }
template <typename T> template <typename T>
inline T *atomic_fetch_add_explicit(Atomic<T *> *a, octa::Ptrdiff op, inline T *atomic_fetch_add_explicit(Atomic<T *> *a, Ptrdiff op,
MemoryOrder ord) { MemoryOrder ord) {
return a->fetch_add(op, ord); return a->fetch_add(op, ord);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_sub(volatile Atomic<T> *a, T op) { atomic_fetch_sub(volatile Atomic<T> *a, T op) {
return a->fetch_sub(op); return a->fetch_sub(op);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_sub(Atomic<T> *a, T op) { atomic_fetch_sub(Atomic<T> *a, T op) {
return a->fetch_sub(op); return a->fetch_sub(op);
} }
template <typename T> template <typename T>
inline T *atomic_fetch_sub(volatile Atomic<T *> *a, octa::Ptrdiff op) { inline T *atomic_fetch_sub(volatile Atomic<T *> *a, Ptrdiff op) {
return a->fetch_sub(op); return a->fetch_sub(op);
} }
template <typename T> template <typename T>
inline T *atomic_fetch_sub(Atomic<T *> *a, octa::Ptrdiff op) { inline T *atomic_fetch_sub(Atomic<T *> *a, Ptrdiff op) {
return a->fetch_sub(op); return a->fetch_sub(op);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_sub_explicit(volatile Atomic<T> *a, T op, atomic_fetch_sub_explicit(volatile Atomic<T> *a, T op,
MemoryOrder ord) { MemoryOrder ord) {
return a->fetch_sub(op, ord); return a->fetch_sub(op, ord);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_sub_explicit(Atomic<T> *a, T op, MemoryOrder ord) { atomic_fetch_sub_explicit(Atomic<T> *a, T op, MemoryOrder ord) {
return a->fetch_sub(op, ord); return a->fetch_sub(op, ord);
} }
template <typename T> template <typename T>
inline T *atomic_fetch_sub_explicit(volatile Atomic<T *> *a, inline T *atomic_fetch_sub_explicit(volatile Atomic<T *> *a,
octa::Ptrdiff op, MemoryOrder ord) { Ptrdiff op, MemoryOrder ord) {
return a->fetch_sub(op, ord); return a->fetch_sub(op, ord);
} }
template <typename T> template <typename T>
inline T *atomic_fetch_sub_explicit(Atomic<T *> *a, octa::Ptrdiff op, inline T *atomic_fetch_sub_explicit(Atomic<T *> *a, Ptrdiff op,
MemoryOrder ord) { MemoryOrder ord) {
return a->fetch_sub(op, ord); return a->fetch_sub(op, ord);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_and(volatile Atomic<T> *a, T op) { atomic_fetch_and(volatile Atomic<T> *a, T op) {
return a->fetch_and(op); return a->fetch_and(op);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_and(Atomic<T> *a, T op) { atomic_fetch_and(Atomic<T> *a, T op) {
return a->fetch_and(op); return a->fetch_and(op);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_and_explicit(volatile Atomic<T> *a, T op, atomic_fetch_and_explicit(volatile Atomic<T> *a, T op,
MemoryOrder ord) { MemoryOrder ord) {
return a->fetch_and(op, ord); return a->fetch_and(op, ord);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_and_explicit(Atomic<T> *a, T op, MemoryOrder ord) { atomic_fetch_and_explicit(Atomic<T> *a, T op, MemoryOrder ord) {
return a->fetch_and(op, ord); return a->fetch_and(op, ord);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_or(volatile Atomic<T> *a, T op) { atomic_fetch_or(volatile Atomic<T> *a, T op) {
return a->fetch_or(op); return a->fetch_or(op);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_or(Atomic<T> *a, T op) { atomic_fetch_or(Atomic<T> *a, T op) {
return a->fetch_or(op); return a->fetch_or(op);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_or_explicit(volatile Atomic<T> *a, T op, atomic_fetch_or_explicit(volatile Atomic<T> *a, T op,
MemoryOrder ord) { MemoryOrder ord) {
return a->fetch_or(op, ord); return a->fetch_or(op, ord);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_or_explicit(Atomic<T> *a, T op, MemoryOrder ord) { atomic_fetch_or_explicit(Atomic<T> *a, T op, MemoryOrder ord) {
return a->fetch_or(op, ord); return a->fetch_or(op, ord);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_xor(volatile Atomic<T> *a, T op) { atomic_fetch_xor(volatile Atomic<T> *a, T op) {
return a->fetch_xor(op); return a->fetch_xor(op);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_xor(Atomic<T> *a, T op) { atomic_fetch_xor(Atomic<T> *a, T op) {
return a->fetch_xor(op); return a->fetch_xor(op);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_xor_explicit(volatile Atomic<T> *a, T op, atomic_fetch_xor_explicit(volatile Atomic<T> *a, T op,
MemoryOrder ord) { MemoryOrder ord) {
return a->fetch_xor(op, ord); return a->fetch_xor(op, ord);
} }
template <typename T> template <typename T>
inline octa::EnableIf<octa::IsIntegral<T>::value && inline EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value, T>
!octa::IsSame<T, bool>::value, T>
atomic_fetch_xor_explicit(Atomic<T> *a, T op, MemoryOrder ord) { atomic_fetch_xor_explicit(Atomic<T> *a, T op, MemoryOrder ord) {
return a->fetch_xor(op, ord); return a->fetch_xor(op, ord);
} }
struct AtomicFlag { struct AtomicFlag {
octa::detail::AtomicBase<bool> p_a; detail::AtomicBase<bool> p_a;
AtomicFlag() = default; AtomicFlag() = default;
@ -858,19 +837,19 @@ struct AtomicFlag {
AtomicFlag &operator=(const AtomicFlag &) volatile = delete; AtomicFlag &operator=(const AtomicFlag &) volatile = delete;
bool test_and_set(MemoryOrder ord = MemoryOrder::seq_cst) volatile { bool test_and_set(MemoryOrder ord = MemoryOrder::seq_cst) volatile {
return octa::detail::atomic_exchange(&p_a, true, ord); return detail::atomic_exchange(&p_a, true, ord);
} }
bool test_and_set(MemoryOrder ord = MemoryOrder::seq_cst) { bool test_and_set(MemoryOrder ord = MemoryOrder::seq_cst) {
return octa::detail::atomic_exchange(&p_a, true, ord); return detail::atomic_exchange(&p_a, true, ord);
} }
void clear(MemoryOrder ord = MemoryOrder::seq_cst) volatile { void clear(MemoryOrder ord = MemoryOrder::seq_cst) volatile {
octa::detail::atomic_store(&p_a, false, ord); detail::atomic_store(&p_a, false, ord);
} }
void clear(MemoryOrder ord = MemoryOrder::seq_cst) { void clear(MemoryOrder ord = MemoryOrder::seq_cst) {
octa::detail::atomic_store(&p_a, false, ord); detail::atomic_store(&p_a, false, ord);
} }
}; };
@ -910,11 +889,11 @@ inline void atomic_flag_clear_explicit(AtomicFlag *a, MemoryOrder ord) {
} }
inline void atomic_thread_fence(MemoryOrder ord) { inline void atomic_thread_fence(MemoryOrder ord) {
octa::detail::atomic_thread_fence(ord); detail::atomic_thread_fence(ord);
} }
inline void atomic_signal_fence(MemoryOrder ord) { inline void atomic_signal_fence(MemoryOrder ord) {
octa::detail::atomic_signal_fence(ord); detail::atomic_signal_fence(ord);
} }
using AtomicBool = Atomic<bool>; using AtomicBool = Atomic<bool>;
@ -922,56 +901,56 @@ using AtomicChar = Atomic<char>;
using AtomicShort = Atomic<short>; using AtomicShort = Atomic<short>;
using AtomicInt = Atomic<int>; using AtomicInt = Atomic<int>;
using AtomicLong = Atomic<long>; using AtomicLong = Atomic<long>;
using AtomicSbyte = Atomic<octa::sbyte>; using AtomicSbyte = Atomic<sbyte>;
using AtomicByte = Atomic<octa::byte>; using AtomicByte = Atomic<byte>;
using AtomicUshort = Atomic<octa::ushort>; using AtomicUshort = Atomic<ushort>;
using AtomicUint = Atomic<octa::uint>; using AtomicUint = Atomic<uint>;
using AtomicUlong = Atomic<octa::ulong>; using AtomicUlong = Atomic<ulong>;
using AtomicLlong = Atomic<octa::llong>; using AtomicLlong = Atomic<llong>;
using AtomicUllong = Atomic<octa::ullong>; using AtomicUllong = Atomic<ullong>;
using AtomicChar16 = Atomic<octa::Char16>; using AtomicChar16 = Atomic<Char16>;
using AtomicChar32 = Atomic<octa::Char32>; using AtomicChar32 = Atomic<Char32>;
using AtomicWchar = Atomic<octa::Wchar>; using AtomicWchar = Atomic<Wchar>;
using AtomicPtrdiff = Atomic<octa::Ptrdiff>; using AtomicPtrdiff = Atomic<Ptrdiff>;
using AtomicSize = Atomic<octa::Size>; using AtomicSize = Atomic<Size>;
using AtomicIntmax = Atomic<octa::Intmax>; using AtomicIntmax = Atomic<Intmax>;
using AtomicUintmax = Atomic<octa::Uintmax>; using AtomicUintmax = Atomic<Uintmax>;
using AtomicIntptr = Atomic<octa::Intptr>; using AtomicIntptr = Atomic<Intptr>;
using AtomicUintptr = Atomic<octa::Uintptr>; using AtomicUintptr = Atomic<Uintptr>;
using AtomicInt8 = Atomic<octa::Int8>; using AtomicInt8 = Atomic<Int8>;
using AtomicInt16 = Atomic<octa::Int16>; using AtomicInt16 = Atomic<Int16>;
using AtomicInt32 = Atomic<octa::Int32>; using AtomicInt32 = Atomic<Int32>;
using AtomicInt64 = Atomic<octa::Int64>; using AtomicInt64 = Atomic<Int64>;
using AtomicUint8 = Atomic<octa::Uint8>; using AtomicUint8 = Atomic<Uint8>;
using AtomicUint16 = Atomic<octa::Uint16>; using AtomicUint16 = Atomic<Uint16>;
using AtomicUint32 = Atomic<octa::Uint32>; using AtomicUint32 = Atomic<Uint32>;
using AtomicUint64 = Atomic<octa::Uint64>; using AtomicUint64 = Atomic<Uint64>;
using AtomicIntLeast8 = Atomic<octa::IntLeast8>; using AtomicIntLeast8 = Atomic<IntLeast8>;
using AtomicIntLeast16 = Atomic<octa::IntLeast16>; using AtomicIntLeast16 = Atomic<IntLeast16>;
using AtomicIntLeast32 = Atomic<octa::IntLeast32>; using AtomicIntLeast32 = Atomic<IntLeast32>;
using AtomicIntLeast64 = Atomic<octa::IntLeast64>; using AtomicIntLeast64 = Atomic<IntLeast64>;
using AtomicUintLeast8 = Atomic<octa::UintLeast8>; using AtomicUintLeast8 = Atomic<UintLeast8>;
using AtomicUintLeast16 = Atomic<octa::UintLeast16>; using AtomicUintLeast16 = Atomic<UintLeast16>;
using AtomicUintLeast32 = Atomic<octa::UintLeast32>; using AtomicUintLeast32 = Atomic<UintLeast32>;
using AtomicUintLeast64 = Atomic<octa::UintLeast64>; using AtomicUintLeast64 = Atomic<UintLeast64>;
using AtomicIntFast8 = Atomic<octa::IntFast8>; using AtomicIntFast8 = Atomic<IntFast8>;
using AtomicIntFast16 = Atomic<octa::IntFast16>; using AtomicIntFast16 = Atomic<IntFast16>;
using AtomicIntFast32 = Atomic<octa::IntFast32>; using AtomicIntFast32 = Atomic<IntFast32>;
using AtomicIntFast64 = Atomic<octa::IntFast64>; using AtomicIntFast64 = Atomic<IntFast64>;
using AtomicUintFast8 = Atomic<octa::UintFast8>; using AtomicUintFast8 = Atomic<UintFast8>;
using AtomicUintFast16 = Atomic<octa::UintFast16>; using AtomicUintFast16 = Atomic<UintFast16>;
using AtomicUintFast32 = Atomic<octa::UintFast32>; using AtomicUintFast32 = Atomic<UintFast32>;
using AtomicUintFast64 = Atomic<octa::UintFast64>; using AtomicUintFast64 = Atomic<UintFast64>;
#define ATOMIC_FLAG_INIT {false} #define ATOMIC_FLAG_INIT {false}
#define ATOMIC_VAR_INIT(v) {v} #define ATOMIC_VAR_INIT(v) {v}

View File

@ -41,8 +41,8 @@ namespace detail {
return ret; return ret;
} }
static inline octa::Size read_digits(const char *&fmt, char *buf) { static inline Size read_digits(const char *&fmt, char *buf) {
octa::Size ret = 0; Size ret = 0;
for (; isdigit(*fmt); ++ret) for (; isdigit(*fmt); ++ret)
*buf++ = *fmt++; *buf++ = *fmt++;
*buf = '\0'; *buf = '\0';
@ -59,7 +59,7 @@ namespace detail {
* 7 .. string * 7 .. string
* 8 .. custom object * 8 .. custom object
*/ */
static constexpr const octa::byte fmt_specs[] = { static constexpr const byte fmt_specs[] = {
/* uppercase spec set */ /* uppercase spec set */
1, 3, 8, 8, /* A B C D */ 1, 3, 8, 8, /* A B C D */
1, 1, 1, 8, /* E F G H */ 1, 1, 1, 8, /* E F G H */
@ -107,23 +107,23 @@ namespace detail {
/* retrieve width/precision */ /* retrieve width/precision */
template<typename T> template<typename T>
bool convert_arg_param(const T &val, int &param, octa::EnableIf< bool convert_arg_param(const T &val, int &param, EnableIf<
octa::IsIntegral<T>::value, bool IsIntegral<T>::value, bool
> = true) { > = true) {
param = int(val); param = int(val);
return true; return true;
} }
template<typename T> template<typename T>
bool convert_arg_param(const T &, int &, octa::EnableIf< bool convert_arg_param(const T &, int &, EnableIf<
!octa::IsIntegral<T>::value, bool !IsIntegral<T>::value, bool
> = true) { > = true) {
assert(false && "invalid argument for width/precision"); assert(false && "invalid argument for width/precision");
return false; return false;
} }
template<typename T> template<typename T>
bool get_arg_param(octa::Size idx, int &param, const T &val) { bool get_arg_param(Size idx, int &param, const T &val) {
if (idx) { if (idx) {
assert(false && "not enough format args"); assert(false && "not enough format args");
return false; return false;
@ -131,7 +131,7 @@ namespace detail {
return convert_arg_param(val, param); return convert_arg_param(val, param);
} }
template<typename T, typename ...A> template<typename T, typename ...A>
bool get_arg_param(octa::Size idx, int &param, const T &val, bool get_arg_param(Size idx, int &param, const T &val,
const A &...args) { const A &...args) {
if (idx) return get_arg_param(idx - 1, param, args...); if (idx) return get_arg_param(idx - 1, param, args...);
return convert_arg_param(val, param); return convert_arg_param(val, param);
@ -144,8 +144,8 @@ struct FormatSpec {
p_nested_escape(escape), p_fmt(fmt) {} p_nested_escape(escape), p_fmt(fmt) {}
template<typename R> template<typename R>
bool read_until_spec(R &writer, octa::Size *wret) { bool read_until_spec(R &writer, Size *wret) {
octa::Size written = 0; Size written = 0;
if (!p_fmt) return false; if (!p_fmt) return false;
while (*p_fmt) { while (*p_fmt) {
if (*p_fmt == '%') { if (*p_fmt == '%') {
@ -164,8 +164,7 @@ struct FormatSpec {
} }
template<typename R> template<typename R>
octa::Size write_spaces(R &writer, octa::Size n, Size write_spaces(R &writer, Size n, bool left, char c = ' ') const {
bool left, char c = ' ') const {
if (left == bool(p_flags & FMT_FLAG_DASH)) return 0; if (left == bool(p_flags & FMT_FLAG_DASH)) return 0;
int r = p_width - int(n); int r = p_width - int(n);
for (int w = p_width - int(n); --w >= 0; writer.put(c)); for (int w = p_width - int(n); --w >= 0; writer.put(c));
@ -177,7 +176,7 @@ struct FormatSpec {
return p_fmt; return p_fmt;
} }
void build_spec(char *buf, const char *spec, octa::Size specn) { void build_spec(char *buf, const char *spec, Size specn) {
*buf++ = '%'; *buf++ = '%';
if (p_flags & FMT_FLAG_DASH ) *buf++ = '-'; if (p_flags & FMT_FLAG_DASH ) *buf++ = '-';
if (p_flags & FMT_FLAG_ZERO ) *buf++ = '0'; if (p_flags & FMT_FLAG_ZERO ) *buf++ = '0';
@ -199,36 +198,36 @@ struct FormatSpec {
bool arg_precision() const { return p_arg_precision; } bool arg_precision() const { return p_arg_precision; }
template<typename ...A> template<typename ...A>
bool set_width(octa::Size idx, const A &...args) { bool set_width(Size idx, const A &...args) {
return octa::detail::get_arg_param(idx, p_width, args...); return detail::get_arg_param(idx, p_width, args...);
} }
template<typename ...A> template<typename ...A>
bool set_precision(octa::Size idx, const A &...args) { bool set_precision(Size idx, const A &...args) {
return octa::detail::get_arg_param(idx, p_precision, args...); return detail::get_arg_param(idx, p_precision, args...);
} }
int flags() const { return p_flags; } int flags() const { return p_flags; }
char spec() const { return p_spec; } char spec() const { return p_spec; }
octa::byte index() const { return p_index; } byte index() const { return p_index; }
const char *nested() const { return p_nested; } const char *nested() const { return p_nested; }
octa::Size nested_len() const { return p_nested_len; } Size nested_len() const { return p_nested_len; }
const char *nested_sep() const { return p_nested_sep; } const char *nested_sep() const { return p_nested_sep; }
octa::Size nested_sep_len() const { return p_nested_sep_len; } Size nested_sep_len() const { return p_nested_sep_len; }
bool is_nested() const { return p_is_nested; } bool is_nested() const { return p_is_nested; }
bool nested_escape() const { return p_nested_escape; } bool nested_escape() const { return p_nested_escape; }
protected: protected:
const char *p_nested = nullptr; const char *p_nested = nullptr;
octa::Size p_nested_len = 0; Size p_nested_len = 0;
const char *p_nested_sep = nullptr; const char *p_nested_sep = nullptr;
octa::Size p_nested_sep_len = 0; Size p_nested_sep_len = 0;
int p_flags = 0; int p_flags = 0;
@ -243,7 +242,7 @@ protected:
char p_spec = '\0'; char p_spec = '\0';
octa::byte p_index = 0; byte p_index = 0;
bool p_is_nested = false; bool p_is_nested = false;
bool p_nested_escape = false; bool p_nested_escape = false;
@ -323,7 +322,7 @@ protected:
if ((*p_fmt == '(') || ((*p_fmt == '-') && (*(p_fmt + 1) == '('))) { if ((*p_fmt == '(') || ((*p_fmt == '-') && (*(p_fmt + 1) == '('))) {
return read_spec_range(); return read_spec_range();
} }
octa::Size ndig = octa::detail::read_digits(p_fmt, p_buf); Size ndig = detail::read_digits(p_fmt, p_buf);
bool havepos = false; bool havepos = false;
p_index = 0; p_index = 0;
@ -332,7 +331,7 @@ protected:
if (ndig <= 0) return false; /* no pos given */ if (ndig <= 0) return false; /* no pos given */
int idx = atoi(p_buf); int idx = atoi(p_buf);
if (idx <= 0 || idx > 255) return false; /* bad index */ if (idx <= 0 || idx > 255) return false; /* bad index */
p_index = octa::byte(idx); p_index = byte(idx);
++p_fmt; ++p_fmt;
havepos = true; havepos = true;
} }
@ -344,17 +343,17 @@ protected:
/* parse flags */ /* parse flags */
p_flags = 0; p_flags = 0;
octa::Size skipd = 0; Size skipd = 0;
if (havepos || !ndig) { if (havepos || !ndig) {
p_flags = octa::detail::parse_fmt_flags(p_fmt, 0); p_flags = detail::parse_fmt_flags(p_fmt, 0);
} else { } else {
for (octa::Size i = 0; i < ndig; ++i) { for (Size i = 0; i < ndig; ++i) {
if (p_buf[i] != '0') break; if (p_buf[i] != '0') break;
++skipd; ++skipd;
} }
if (skipd) p_flags = FMT_FLAG_ZERO; if (skipd) p_flags = FMT_FLAG_ZERO;
if (skipd == ndig) if (skipd == ndig)
p_flags = octa::detail::parse_fmt_flags(p_fmt, p_flags); p_flags = detail::parse_fmt_flags(p_fmt, p_flags);
} }
/* parse width */ /* parse width */
@ -364,7 +363,7 @@ protected:
if (!havepos && ndig && (ndig - skipd)) { if (!havepos && ndig && (ndig - skipd)) {
p_width = atoi(p_buf + skipd); p_width = atoi(p_buf + skipd);
p_has_width = true; p_has_width = true;
} else if (octa::detail::read_digits(p_fmt, p_buf)) { } else if (detail::read_digits(p_fmt, p_buf)) {
p_width = atoi(p_buf); p_width = atoi(p_buf);
p_has_width = true; p_has_width = true;
} else if (*p_fmt == '*') { } else if (*p_fmt == '*') {
@ -379,7 +378,7 @@ protected:
if (*p_fmt != '.') goto fmtchar; if (*p_fmt != '.') goto fmtchar;
++p_fmt; ++p_fmt;
if (octa::detail::read_digits(p_fmt, p_buf)) { if (detail::read_digits(p_fmt, p_buf)) {
p_precision = atoi(p_buf); p_precision = atoi(p_buf);
p_has_precision = true; p_has_precision = true;
} else if (*p_fmt == '*') { } else if (*p_fmt == '*') {
@ -391,8 +390,8 @@ protected:
p_spec = *p_fmt++; p_spec = *p_fmt++;
/* make sure we're testing on a signed byte - our mapping only /* make sure we're testing on a signed byte - our mapping only
* tests values up to 127 */ * tests values up to 127 */
octa::sbyte sp = p_spec; sbyte sp = p_spec;
return (sp >= 65) && (octa::detail::fmt_specs[sp - 65] != 0); return (sp >= 65) && (detail::fmt_specs[sp - 65] != 0);
} }
const char *p_fmt; const char *p_fmt;
@ -401,24 +400,24 @@ protected:
namespace detail { namespace detail {
template<typename R, typename T> template<typename R, typename T>
static inline octa::Ptrdiff write_u(R &writer, const FormatSpec *fl, static inline Ptrdiff write_u(R &writer, const FormatSpec *fl,
bool neg, T val) { bool neg, T val) {
char buf[20]; char buf[20];
octa::Ptrdiff r = 0; Ptrdiff r = 0;
octa::Size n = 0; Size n = 0;
char spec = fl->spec(); char spec = fl->spec();
if (spec == 's') spec = 'd'; if (spec == 's') spec = 'd';
octa::byte specn = octa::detail::fmt_specs[spec - 65]; byte specn = detail::fmt_specs[spec - 65];
if (specn <= 2 || specn > 7) { if (specn <= 2 || specn > 7) {
assert(false && "cannot format integers with the given spec"); assert(false && "cannot format integers with the given spec");
return -1; return -1;
} }
int base = octa::detail::fmt_bases[specn]; int base = detail::fmt_bases[specn];
if (!val) buf[n++] = '0'; if (!val) buf[n++] = '0';
for (; val; val /= base) for (; val; val /= base)
buf[n++] = octa::detail::fmt_digits[spec >= 'a'][val % base]; buf[n++] = detail::fmt_digits[spec >= 'a'][val % base];
r = n; r = n;
int flags = fl->flags(); int flags = fl->flags();
@ -431,7 +430,7 @@ namespace detail {
const char *pfx = nullptr; const char *pfx = nullptr;
int pfxlen = 0; int pfxlen = 0;
if (flags & FMT_FLAG_HASH && spec != 'd') { if (flags & FMT_FLAG_HASH && spec != 'd') {
pfx = octa::detail::fmt_intpfx[spec >= 'a'][specn - 3]; pfx = detail::fmt_intpfx[spec >= 'a'][specn - 3];
pfxlen = !!pfx[1] + 1; pfxlen = !!pfx[1] + 1;
r += pfxlen; r += pfxlen;
} }
@ -451,52 +450,43 @@ namespace detail {
} }
template<typename R, typename ...A> template<typename R, typename ...A>
static octa::Ptrdiff format_impl(R &writer, octa::Size &fmtn, static Ptrdiff format_impl(R &writer, Size &fmtn, bool escape,
bool escape, const char *fmt, const char *fmt, const A &...args);
const A &...args);
template<typename T, typename = octa::RangeOf<T>> template<typename T, typename = RangeOf<T>>
static octa::True test_fmt_range(int); static True test_fmt_range(int);
template<typename> template<typename>
static octa::False test_fmt_range(...); static False test_fmt_range(...);
template<typename T> template<typename T>
using FmtRangeTest = decltype(test_fmt_range<T>(0)); using FmtRangeTest = decltype(test_fmt_range<T>(0));
template<typename R, typename T> template<typename R, typename T>
static inline octa::Ptrdiff format_ritem(R &writer, octa::Size &fmtn, static inline Ptrdiff format_ritem(R &writer, Size &fmtn, bool esc,
bool esc, const char *fmt, const T &item) {
const char *fmt,
const T &item) {
return format_impl(writer, fmtn, esc, fmt, item); return format_impl(writer, fmtn, esc, fmt, item);
} }
template<typename R, typename T, typename U> template<typename R, typename T, typename U>
static inline octa::Ptrdiff format_ritem(R &writer, octa::Size &fmtn, static inline Ptrdiff format_ritem(R &writer, Size &fmtn, bool esc,
bool esc,
const char *fmt, const char *fmt,
const octa::Pair<T, U> &pair) { const Pair<T, U> &pair) {
return format_impl(writer, fmtn, esc, fmt, pair.first, pair.second); return format_impl(writer, fmtn, esc, fmt, pair.first, pair.second);
} }
template<typename R, typename T> template<typename R, typename T>
static inline octa::Ptrdiff write_range(R &writer, static inline Ptrdiff write_range(R &writer, const FormatSpec *fl,
const FormatSpec *fl, bool escape, const char *sep,
bool escape, Size seplen, const T &val,
const char *sep, EnableIf<FmtRangeTest<T>::value,
octa::Size seplen, bool> = true) {
const T &val,
octa::EnableIf<
FmtRangeTest<T>::value,
bool
> = true) {
auto range = octa::iter(val); auto range = octa::iter(val);
if (range.empty()) return 0; if (range.empty()) return 0;
octa::Ptrdiff ret = 0; Ptrdiff ret = 0;
octa::Size fmtn = 0; Size fmtn = 0;
/* test first item */ /* test first item */
octa::Ptrdiff fret = format_ritem(writer, fmtn, escape, Ptrdiff fret = format_ritem(writer, fmtn, escape, fl->rest(),
fl->rest(), range.front()); range.front());
if (fret < 0) return fret; if (fret < 0) return fret;
ret += fret; ret += fret;
range.pop_front(); range.pop_front();
@ -515,21 +505,18 @@ namespace detail {
} }
template<typename R, typename T> template<typename R, typename T>
static inline octa::Ptrdiff write_range(R &, const FormatSpec *, bool, static inline Ptrdiff write_range(R &, const FormatSpec *, bool,
const char *, octa::Size, const char *, Size, const T &,
const T &, EnableIf<!FmtRangeTest<T>::value,
octa::EnableIf< bool> = true) {
!FmtRangeTest<T>::value,
bool
> = true) {
assert(false && "invalid value for ranged format"); assert(false && "invalid value for ranged format");
return -1; return -1;
} }
template<typename T, template<typename T,
typename = decltype(octa::to_string(octa::declval<T>())) typename = decltype(octa::to_string(declval<T>()))
> static octa::True test_fmt_tostr(int); > static True test_fmt_tostr(int);
template<typename> static octa::False test_fmt_tostr(...); template<typename> static False test_fmt_tostr(...);
template<typename T> template<typename T>
using FmtTostrTest = decltype(test_fmt_tostr<T>(0)); using FmtTostrTest = decltype(test_fmt_tostr<T>(0));
@ -549,15 +536,15 @@ namespace detail {
static inline const char *escape_fmt_char(char v, char quote) { static inline const char *escape_fmt_char(char v, char quote) {
if ((v >= 0 && v < 0x20) || (v == quote)) { if ((v >= 0 && v < 0x20) || (v == quote)) {
return fmt_escapes[octa::Size(v)]; return fmt_escapes[Size(v)];
} else if (v == 0x7F) { } else if (v == 0x7F) {
return "\\x7F"; return "\\x7F";
} }
return nullptr; return nullptr;
} }
static inline octa::String escape_fmt_str(const char *val) { static inline String escape_fmt_str(const char *val) {
octa::String ret; String ret;
ret.push('"'); ret.push('"');
while (*val) { while (*val) {
const char *esc = escape_fmt_char(*val, '"'); const char *esc = escape_fmt_char(*val, '"');
@ -572,7 +559,7 @@ namespace detail {
} }
template<typename R> template<typename R>
struct FmtWriteRange: octa::OutputRange<FmtWriteRange<R>, char> { struct FmtWriteRange: OutputRange<FmtWriteRange<R>, char> {
FmtWriteRange() = delete; FmtWriteRange() = delete;
FmtWriteRange(R &out): p_out(out), p_written(0) {} FmtWriteRange(R &out): p_out(out), p_written(0) {}
bool put(char v) { bool put(char v) {
@ -580,15 +567,15 @@ namespace detail {
p_written += ret; p_written += ret;
return ret; return ret;
} }
octa::Size put_n(const char *v, octa::Size n) { Size put_n(const char *v, Size n) {
octa::Size ret = p_out.put_n(v, n); Size ret = p_out.put_n(v, n);
p_written += ret; p_written += ret;
return ret; return ret;
} }
octa::Size get_written() const { return p_written; } Size get_written() const { return p_written; }
private: private:
R &p_out; R &p_out;
octa::Size p_written; Size p_written;
}; };
template<typename T, typename U> template<typename T, typename U>
@ -602,21 +589,20 @@ namespace detail {
static constexpr bool value = (sizeof(test<T, U>(0)) == sizeof(char)); static constexpr bool value = (sizeof(test<T, U>(0)) == sizeof(char));
}; };
struct WriteSpec: octa::FormatSpec { struct WriteSpec: FormatSpec {
WriteSpec(): octa::FormatSpec() {} WriteSpec(): FormatSpec() {}
WriteSpec(const char *fmt, bool esc): octa::FormatSpec(fmt, esc) {} WriteSpec(const char *fmt, bool esc): FormatSpec(fmt, esc) {}
/* C string */ /* C string */
template<typename R> template<typename R>
octa::Ptrdiff write(R &writer, bool escape, const char *val, Ptrdiff write(R &writer, bool escape, const char *val, Size n) {
octa::Size n) {
if (escape) { if (escape) {
octa::String esc = escape_fmt_str(val); String esc = escape_fmt_str(val);
return write(writer, false, (const char *)esc.data(), return write(writer, false, (const char *)esc.data(),
esc.size()); esc.size());
} }
if (this->precision()) n = this->precision(); if (this->precision()) n = this->precision();
octa::Ptrdiff r = n; Ptrdiff r = n;
r += this->write_spaces(writer, n, true); r += this->write_spaces(writer, n, true);
writer.put_n(val, n); writer.put_n(val, n);
r += this->write_spaces(writer, n, false); r += this->write_spaces(writer, n, false);
@ -624,7 +610,7 @@ namespace detail {
} }
template<typename R> template<typename R>
octa::Ptrdiff write(R &writer, bool escape, const char *val) { Ptrdiff write(R &writer, bool escape, const char *val) {
if (this->spec() != 's') { if (this->spec() != 's') {
assert(false && "cannot print strings with the given spec"); assert(false && "cannot print strings with the given spec");
return -1; return -1;
@ -634,8 +620,7 @@ namespace detail {
/* OctaSTD string */ /* OctaSTD string */
template<typename R, typename A> template<typename R, typename A>
octa::Ptrdiff write(R &writer, bool escape, Ptrdiff write(R &writer, bool escape, const AnyString<A> &val) {
const octa::AnyString<A> &val) {
if (this->spec() != 's') { if (this->spec() != 's') {
assert(false && "cannot print strings with the given spec"); assert(false && "cannot print strings with the given spec");
return -1; return -1;
@ -645,7 +630,7 @@ namespace detail {
/* character */ /* character */
template<typename R> template<typename R>
octa::Ptrdiff write(R &writer, bool escape, char val) { Ptrdiff write(R &writer, bool escape, char val) {
if (this->spec() != 's' && this->spec() != 'c') { if (this->spec() != 's' && this->spec() != 'c') {
assert(false && "cannot print chars with the given spec"); assert(false && "cannot print chars with the given spec");
return -1; return -1;
@ -655,13 +640,13 @@ namespace detail {
if (esc) { if (esc) {
char buf[6]; char buf[6];
buf[0] = '\''; buf[0] = '\'';
octa::Size elen = strlen(esc); Size elen = strlen(esc);
memcpy(buf + 1, esc, elen); memcpy(buf + 1, esc, elen);
buf[elen + 1] = '\''; buf[elen + 1] = '\'';
return write(writer, false, (const char *)buf, elen + 2); return write(writer, false, (const char *)buf, elen + 2);
} }
} }
octa::Ptrdiff r = 1 + escape * 2; Ptrdiff r = 1 + escape * 2;
r += this->write_spaces(writer, 1 + escape * 2, true); r += this->write_spaces(writer, 1 + escape * 2, true);
if (escape) { if (escape) {
writer.put('\''); writer.put('\'');
@ -674,7 +659,7 @@ namespace detail {
/* bool */ /* bool */
template<typename R> template<typename R>
octa::Ptrdiff write(R &writer, bool, bool val) { Ptrdiff write(R &writer, bool, bool val) {
if (this->spec() == 's') if (this->spec() == 's')
return write(writer, ("false\0true") + (6 * val)); return write(writer, ("false\0true") + (6 * val));
else else
@ -683,32 +668,32 @@ namespace detail {
/* signed integers */ /* signed integers */
template<typename R, typename T> template<typename R, typename T>
octa::Ptrdiff write(R &writer, bool, T val, octa::EnableIf< Ptrdiff write(R &writer, bool, T val, EnableIf<
octa::IsIntegral<T>::value && octa::IsSigned<T>::value, bool IsIntegral<T>::value && IsSigned<T>::value, bool
> = true) { > = true) {
using UT = octa::MakeUnsigned<T>; using UT = MakeUnsigned<T>;
return octa::detail::write_u(writer, this, val < 0, return detail::write_u(writer, this, val < 0,
(val < 0) ? UT(-val) : UT(val)); (val < 0) ? (UT)(-val) : (UT)(val));
} }
/* unsigned integers */ /* unsigned integers */
template<typename R, typename T> template<typename R, typename T>
octa::Ptrdiff write(R &writer, bool, T val, octa::EnableIf< Ptrdiff write(R &writer, bool, T val, EnableIf<
octa::IsIntegral<T>::value && octa::IsUnsigned<T>::value, bool IsIntegral<T>::value && IsUnsigned<T>::value, bool
> = true) { > = true) {
return octa::detail::write_u(writer, this, false, val); return detail::write_u(writer, this, false, val);
} }
template<typename R, typename T, template<typename R, typename T,
bool Long = octa::IsSame<T, octa::ldouble>::value bool Long = IsSame<T, ldouble>::value
> octa::Ptrdiff write(R &writer, bool, T val, octa::EnableIf< > Ptrdiff write(R &writer, bool, T val, EnableIf<
octa::IsFloatingPoint<T>::value, bool IsFloatingPoint<T>::value, bool
> = true) { > = true) {
char buf[16], rbuf[128]; char buf[16], rbuf[128];
char fmtspec[Long + 1]; char fmtspec[Long + 1];
fmtspec[Long] = this->spec(); fmtspec[Long] = this->spec();
octa::byte specn = octa::detail::fmt_specs[this->spec() - 65]; byte specn = detail::fmt_specs[this->spec() - 65];
if (specn != 1 && specn != 7) { if (specn != 1 && specn != 7) {
assert(false && "cannot format floats with the given spec"); assert(false && "cannot format floats with the given spec");
return -1; return -1;
@ -717,12 +702,12 @@ namespace detail {
if (Long) fmtspec[0] = 'L'; if (Long) fmtspec[0] = 'L';
this->build_spec(buf, fmtspec, sizeof(fmtspec)); this->build_spec(buf, fmtspec, sizeof(fmtspec));
octa::Ptrdiff ret = snprintf(rbuf, sizeof(rbuf), buf, Ptrdiff ret = snprintf(rbuf, sizeof(rbuf), buf,
this->width(), this->width(),
this->has_precision() ? this->precision() : 6, val); this->has_precision() ? this->precision() : 6, val);
char *dbuf = nullptr; char *dbuf = nullptr;
if (octa::Size(ret) >= sizeof(rbuf)) { if (Size(ret) >= sizeof(rbuf)) {
/* this should typically never happen */ /* this should typically never happen */
dbuf = (char *)malloc(ret + 1); dbuf = (char *)malloc(ret + 1);
ret = snprintf(dbuf, ret + 1, buf, this->width(), ret = snprintf(dbuf, ret + 1, buf, this->width(),
@ -735,18 +720,18 @@ namespace detail {
/* pointer value */ /* pointer value */
template<typename R, typename T> template<typename R, typename T>
octa::Ptrdiff write(R &writer, bool, T *val) { Ptrdiff write(R &writer, bool, T *val) {
if (this->p_spec == 's') { if (this->p_spec == 's') {
this->p_spec = 'x'; this->p_spec = 'x';
this->p_flags |= FMT_FLAG_HASH; this->p_flags |= FMT_FLAG_HASH;
} }
return write(writer, false, octa::Size(val)); return write(writer, false, Size(val));
} }
/* generic value */ /* generic value */
template<typename R, typename T> template<typename R, typename T>
octa::Ptrdiff write(R &writer, bool, const T &val, octa::EnableIf< Ptrdiff write(R &writer, bool, const T &val, EnableIf<
!octa::IsArithmetic<T>::value && FmtTostrTest<T>::value && !IsArithmetic<T>::value && FmtTostrTest<T>::value &&
!FmtTofmtTest<T, FmtWriteRange<R>>::value, bool !FmtTofmtTest<T, FmtWriteRange<R>>::value, bool
> = true) { > = true) {
if (this->spec() != 's') { if (this->spec() != 's') {
@ -758,8 +743,8 @@ namespace detail {
/* custom format case */ /* custom format case */
template<typename R, typename T> template<typename R, typename T>
octa::Ptrdiff write(R &writer, bool, const T &val, Ptrdiff write(R &writer, bool, const T &val,
octa::EnableIf<FmtTofmtTest<T, FmtWriteRange<R>>::value, bool EnableIf<FmtTofmtTest<T, FmtWriteRange<R>>::value, bool
> = true) { > = true) {
FmtWriteRange<R> sink(writer); FmtWriteRange<R> sink(writer);
if (!val.to_format(sink, *this)) return -1; if (!val.to_format(sink, *this)) return -1;
@ -768,8 +753,8 @@ namespace detail {
/* generic failure case */ /* generic failure case */
template<typename R, typename T> template<typename R, typename T>
octa::Ptrdiff write(R &, bool, const T &, octa::EnableIf< Ptrdiff write(R &, bool, const T &, EnableIf<
!octa::IsArithmetic<T>::value && !FmtTostrTest<T>::value, bool !IsArithmetic<T>::value && !FmtTostrTest<T>::value, bool
> = true) { > = true) {
assert(false && "value cannot be formatted"); assert(false && "value cannot be formatted");
return -1; return -1;
@ -777,7 +762,7 @@ namespace detail {
/* actual writer */ /* actual writer */
template<typename R, typename T> template<typename R, typename T>
octa::Ptrdiff write_arg(R &writer, octa::Size idx, const T &val) { Ptrdiff write_arg(R &writer, Size idx, const T &val) {
if (idx) { if (idx) {
assert(false && "not enough format args"); assert(false && "not enough format args");
return -1; return -1;
@ -786,7 +771,7 @@ namespace detail {
} }
template<typename R, typename T, typename ...A> template<typename R, typename T, typename ...A>
octa::Ptrdiff write_arg(R &writer, octa::Size idx, const T &val, Ptrdiff write_arg(R &writer, Size idx, const T &val,
const A &...args) { const A &...args) {
if (idx) return write_arg(writer, idx - 1, args...); if (idx) return write_arg(writer, idx - 1, args...);
return write(writer, this->p_nested_escape, val); return write(writer, this->p_nested_escape, val);
@ -794,47 +779,42 @@ namespace detail {
/* range writer */ /* range writer */
template<typename R, typename T> template<typename R, typename T>
octa::Ptrdiff write_range(R &writer, octa::Size idx, Ptrdiff write_range(R &writer, Size idx, const char *sep,
const char *sep, octa::Size seplen, Size seplen, const T &val) {
const T &val) {
if (idx) { if (idx) {
assert(false && "not enough format args"); assert(false && "not enough format args");
return -1; return -1;
} }
return octa::detail::write_range(writer, this, return detail::write_range(writer, this, this->p_nested_escape,
this->p_nested_escape, sep, seplen, val); sep, seplen, val);
} }
template<typename R, typename T, typename ...A> template<typename R, typename T, typename ...A>
octa::Ptrdiff write_range(R &writer, octa::Size idx, Ptrdiff write_range(R &writer, Size idx, const char *sep,
const char *sep, octa::Size seplen, Size seplen, const T &val, const A &...args) {
const T &val,
const A &...args) {
if (idx) return write_range(writer, idx - 1, sep, seplen, args...); if (idx) return write_range(writer, idx - 1, sep, seplen, args...);
return octa::detail::write_range(writer, this, return detail::write_range(writer, this,
this->p_nested_escape, sep, seplen, val); this->p_nested_escape, sep, seplen, val);
} }
}; };
template<typename R, typename ...A> template<typename R, typename ...A>
static inline octa::Ptrdiff format_impl(R &writer, octa::Size &fmtn, static inline Ptrdiff format_impl(R &writer, Size &fmtn, bool escape,
bool escape, const char *fmt, const A &...args) {
const char *fmt, Size argidx = 1, retn = 0, twr = 0;
const A &...args) { Ptrdiff written = 0;
octa::Size argidx = 1, retn = 0, twr = 0; detail::WriteSpec spec(fmt, escape);
octa::Ptrdiff written = 0;
octa::detail::WriteSpec spec(fmt, escape);
while (spec.read_until_spec(writer, &twr)) { while (spec.read_until_spec(writer, &twr)) {
written += twr; written += twr;
octa::Size argpos = spec.index(); Size argpos = spec.index();
if (spec.is_nested()) { if (spec.is_nested()) {
if (!argpos) argpos = argidx++; if (!argpos) argpos = argidx++;
/* FIXME: figure out a better way */ /* FIXME: figure out a better way */
char new_fmt[256]; char new_fmt[256];
memcpy(new_fmt, spec.nested(), spec.nested_len()); memcpy(new_fmt, spec.nested(), spec.nested_len());
new_fmt[spec.nested_len()] = '\0'; new_fmt[spec.nested_len()] = '\0';
octa::detail::WriteSpec nspec(new_fmt, spec.nested_escape()); detail::WriteSpec nspec(new_fmt, spec.nested_escape());
octa::Ptrdiff sw = nspec.write_range(writer, argpos - 1, Ptrdiff sw = nspec.write_range(writer, argpos - 1,
spec.nested_sep(), spec.nested_sep_len(), args...); spec.nested_sep(), spec.nested_sep_len(), args...);
if (sw < 0) return sw; if (sw < 0) return sw;
written += sw; written += sw;
@ -871,7 +851,7 @@ namespace detail {
return -1; return -1;
} }
} }
octa::Ptrdiff sw = spec.write_arg(writer, argpos - 1, args...); Ptrdiff sw = spec.write_arg(writer, argpos - 1, args...);
if (sw < 0) return sw; if (sw < 0) return sw;
written += sw; written += sw;
} }
@ -881,10 +861,10 @@ namespace detail {
} }
template<typename R, typename ...A> template<typename R, typename ...A>
static inline octa::Ptrdiff format_impl(R &writer, octa::Size &fmtn, static inline Ptrdiff format_impl(R &writer, Size &fmtn, bool,
bool, const char *fmt) { const char *fmt) {
octa::Size written = 0; Size written = 0;
octa::detail::WriteSpec spec(fmt, false); detail::WriteSpec spec(fmt, false);
if (spec.read_until_spec(writer, &written)) return -1; if (spec.read_until_spec(writer, &written)) return -1;
fmtn = 0; fmtn = 0;
return written; return written;
@ -892,28 +872,26 @@ namespace detail {
} /* namespace detail */ } /* namespace detail */
template<typename R, typename ...A> template<typename R, typename ...A>
static inline octa::Ptrdiff format(R &&writer, octa::Size &fmtn, static inline Ptrdiff format(R &&writer, Size &fmtn, const char *fmt,
const char *fmt, const A &...args) { const A &...args) {
return octa::detail::format_impl(writer, fmtn, false, fmt, args...); return detail::format_impl(writer, fmtn, false, fmt, args...);
} }
template<typename R, typename AL, typename ...A> template<typename R, typename AL, typename ...A>
octa::Ptrdiff format(R &&writer, octa::Size &fmtn, Ptrdiff format(R &&writer, Size &fmtn, const AnyString<AL> &fmt,
const octa::AnyString<AL> &fmt,
const A &...args) { const A &...args) {
return format(writer, fmtn, fmt.data(), args...); return format(writer, fmtn, fmt.data(), args...);
} }
template<typename R, typename ...A> template<typename R, typename ...A>
octa::Ptrdiff format(R &&writer, const char *fmt, const A &...args) { Ptrdiff format(R &&writer, const char *fmt, const A &...args) {
octa::Size fmtn = 0; Size fmtn = 0;
return format(writer, fmtn, fmt, args...); return format(writer, fmtn, fmt, args...);
} }
template<typename R, typename AL, typename ...A> template<typename R, typename AL, typename ...A>
octa::Ptrdiff format(R &&writer, const octa::AnyString<AL> &fmt, Ptrdiff format(R &&writer, const AnyString<AL> &fmt, const A &...args) {
const A &...args) { Size fmtn = 0;
octa::Size fmtn = 0;
return format(writer, fmtn, fmt.data(), args...); return format(writer, fmtn, fmt.data(), args...);
} }

View File

@ -96,8 +96,8 @@ template<typename T> BinaryNegate<T> not2(const T &fn) {
/* endian swap */ /* endian swap */
template<typename T, octa::Size N = sizeof(T), template<typename T, Size N = sizeof(T),
bool IsNum = octa::IsArithmetic<T>::value bool IsNum = IsArithmetic<T>::value
> struct EndianSwap; > struct EndianSwap;
template<typename T> template<typename T>
@ -107,7 +107,7 @@ struct EndianSwap<T, 2, true> {
T operator()(T v) const { T operator()(T v) const {
union { T iv; uint16_t sv; } u; union { T iv; uint16_t sv; } u;
u.iv = v; u.iv = v;
u.sv = octa::endian_swap16(u.sv); u.sv = endian_swap16(u.sv);
return u.iv; return u.iv;
} }
}; };
@ -119,7 +119,7 @@ struct EndianSwap<T, 4, true> {
T operator()(T v) const { T operator()(T v) const {
union { T iv; uint32_t sv; } u; union { T iv; uint32_t sv; } u;
u.iv = v; u.iv = v;
u.sv = octa::endian_swap32(u.sv); u.sv = endian_swap32(u.sv);
return u.iv; return u.iv;
} }
}; };
@ -131,7 +131,7 @@ struct EndianSwap<T, 8, true> {
T operator()(T v) const { T operator()(T v) const {
union { T iv; uint64_t sv; } u; union { T iv; uint64_t sv; } u;
u.iv = v; u.iv = v;
u.sv = octa::endian_swap64(u.sv); u.sv = endian_swap64(u.sv);
return u.iv; return u.iv;
} }
}; };
@ -140,8 +140,8 @@ template<typename T>
T endian_swap(T x) { return EndianSwap<T>()(x); } T endian_swap(T x) { return EndianSwap<T>()(x); }
namespace detail { namespace detail {
template<typename T, octa::Size N = sizeof(T), template<typename T, Size N = sizeof(T),
bool IsNum = octa::IsArithmetic<T>::value bool IsNum = IsArithmetic<T>::value
> struct EndianSame; > struct EndianSame;
template<typename T> template<typename T>
@ -165,11 +165,11 @@ namespace detail {
} }
#if OCTA_BYTE_ORDER == OCTA_ENDIAN_LIL #if OCTA_BYTE_ORDER == OCTA_ENDIAN_LIL
template<typename T> struct FromLilEndian: octa::detail::EndianSame<T> {}; template<typename T> struct FromLilEndian: detail::EndianSame<T> {};
template<typename T> struct FromBigEndian: EndianSwap<T> {}; template<typename T> struct FromBigEndian: EndianSwap<T> {};
#else #else
template<typename T> struct FromLilEndian: EndianSwap<T> {}; template<typename T> struct FromLilEndian: EndianSwap<T> {};
template<typename T> struct FromBigEndian: octa::detail::EndianSame<T> {}; template<typename T> struct FromBigEndian: detail::EndianSame<T> {};
#endif #endif
template<typename T> T from_lil_endian(T x) { return FromLilEndian<T>()(x); } template<typename T> T from_lil_endian(T x) { return FromLilEndian<T>()(x); }
@ -179,9 +179,9 @@ template<typename T> T from_big_endian(T x) { return FromBigEndian<T>()(x); }
template<typename T> struct ToHash { template<typename T> struct ToHash {
using Argument = T; using Argument = T;
using Result = octa::Size; using Result = Size;
octa::Size operator()(const T &v) const { Size operator()(const T &v) const {
return v.to_hash(); return v.to_hash();
} }
}; };
@ -189,15 +189,15 @@ template<typename T> struct ToHash {
namespace detail { namespace detail {
template<typename T> struct ToHashBase { template<typename T> struct ToHashBase {
using Argument = T; using Argument = T;
using Result = octa::Size; using Result = Size;
octa::Size operator()(T v) const { Size operator()(T v) const {
return octa::Size(v); return Size(v);
} }
}; };
} }
#define OCTA_HASH_BASIC(T) template<> struct ToHash<T>: octa::detail::ToHashBase<T> {}; #define OCTA_HASH_BASIC(T) template<> struct ToHash<T>: detail::ToHashBase<T> {};
OCTA_HASH_BASIC(bool) OCTA_HASH_BASIC(bool)
OCTA_HASH_BASIC(char) OCTA_HASH_BASIC(char)
@ -205,35 +205,35 @@ OCTA_HASH_BASIC(short)
OCTA_HASH_BASIC(int) OCTA_HASH_BASIC(int)
OCTA_HASH_BASIC(long) OCTA_HASH_BASIC(long)
OCTA_HASH_BASIC(octa::sbyte) OCTA_HASH_BASIC(sbyte)
OCTA_HASH_BASIC(octa::byte) OCTA_HASH_BASIC(byte)
OCTA_HASH_BASIC(octa::ushort) OCTA_HASH_BASIC(ushort)
OCTA_HASH_BASIC(octa::uint) OCTA_HASH_BASIC(uint)
OCTA_HASH_BASIC(octa::ulong) OCTA_HASH_BASIC(ulong)
OCTA_HASH_BASIC(octa::Char16) OCTA_HASH_BASIC(Char16)
OCTA_HASH_BASIC(octa::Char32) OCTA_HASH_BASIC(Char32)
OCTA_HASH_BASIC(octa::Wchar) OCTA_HASH_BASIC(Wchar)
#undef OCTA_HASH_BASIC #undef OCTA_HASH_BASIC
namespace detail { namespace detail {
static inline Size mem_hash(const void *p, octa::Size l) { static inline Size mem_hash(const void *p, Size l) {
const octa::byte *d = (const octa::byte *)p; const byte *d = (const byte *)p;
octa::Size h = 5381; Size h = 5381;
for (Size i = 0; i < l; ++i) h = ((h << 5) + h) ^ d[i]; for (Size i = 0; i < l; ++i) h = ((h << 5) + h) ^ d[i];
return h; return h;
} }
template<typename T, octa::Size = sizeof(T) / sizeof(octa::Size)> template<typename T, Size = sizeof(T) / sizeof(Size)>
struct ScalarHash; struct ScalarHash;
template<typename T> struct ScalarHash<T, 0> { template<typename T> struct ScalarHash<T, 0> {
using Argument = T; using Argument = T;
using Result = octa::Size; using Result = Size;
octa::Size operator()(T v) const { Size operator()(T v) const {
union { T v; octa::Size h; } u; union { T v; Size h; } u;
u.h = 0; u.h = 0;
u.v = v; u.v = v;
return u.h; return u.h;
@ -242,10 +242,10 @@ namespace detail {
template<typename T> struct ScalarHash<T, 1> { template<typename T> struct ScalarHash<T, 1> {
using Argument = T; using Argument = T;
using Result = octa::Size; using Result = Size;
octa::Size operator()(T v) const { Size operator()(T v) const {
union { T v; octa::Size h; } u; union { T v; Size h; } u;
u.v = v; u.v = v;
return u.h; return u.h;
} }
@ -253,10 +253,10 @@ namespace detail {
template<typename T> struct ScalarHash<T, 2> { template<typename T> struct ScalarHash<T, 2> {
using Argument = T; using Argument = T;
using Result = octa::Size; using Result = Size;
octa::Size operator()(T v) const { Size operator()(T v) const {
union { T v; struct { octa::Size h1, h2; }; } u; union { T v; struct { Size h1, h2; }; } u;
u.v = v; u.v = v;
return mem_hash((const void *)&u, sizeof(u)); return mem_hash((const void *)&u, sizeof(u));
} }
@ -264,10 +264,10 @@ namespace detail {
template<typename T> struct ScalarHash<T, 3> { template<typename T> struct ScalarHash<T, 3> {
using Argument = T; using Argument = T;
using Result = octa::Size; using Result = Size;
octa::Size operator()(T v) const { Size operator()(T v) const {
union { T v; struct { octa::Size h1, h2, h3; }; } u; union { T v; struct { Size h1, h2, h3; }; } u;
u.v = v; u.v = v;
return mem_hash((const void *)&u, sizeof(u)); return mem_hash((const void *)&u, sizeof(u));
} }
@ -275,76 +275,76 @@ namespace detail {
template<typename T> struct ScalarHash<T, 4> { template<typename T> struct ScalarHash<T, 4> {
using Argument = T; using Argument = T;
using Result = octa::Size; using Result = Size;
octa::Size operator()(T v) const { Size operator()(T v) const {
union { T v; struct { octa::Size h1, h2, h3, h4; }; } u; union { T v; struct { Size h1, h2, h3, h4; }; } u;
u.v = v; u.v = v;
return mem_hash((const void *)&u, sizeof(u)); return mem_hash((const void *)&u, sizeof(u));
} }
}; };
} /* namespace detail */ } /* namespace detail */
template<> struct ToHash<octa::llong>: octa::detail::ScalarHash<octa::llong> {}; template<> struct ToHash<llong>: detail::ScalarHash<llong> {};
template<> struct ToHash<octa::ullong>: octa::detail::ScalarHash<octa::ullong> {}; template<> struct ToHash<ullong>: detail::ScalarHash<ullong> {};
template<> struct ToHash<float>: octa::detail::ScalarHash<float> { template<> struct ToHash<float>: detail::ScalarHash<float> {
octa::Size operator()(float v) const { Size operator()(float v) const {
if (v == 0) return 0; if (v == 0) return 0;
return octa::detail::ScalarHash<float>::operator()(v); return detail::ScalarHash<float>::operator()(v);
} }
}; };
template<> struct ToHash<double>: octa::detail::ScalarHash<double> { template<> struct ToHash<double>: detail::ScalarHash<double> {
octa::Size operator()(double v) const { Size operator()(double v) const {
if (v == 0) return 0; if (v == 0) return 0;
return octa::detail::ScalarHash<double>::operator()(v); return detail::ScalarHash<double>::operator()(v);
} }
}; };
template<> struct ToHash<octa::ldouble>: octa::detail::ScalarHash<octa::ldouble> { template<> struct ToHash<ldouble>: detail::ScalarHash<ldouble> {
octa::Size operator()(octa::ldouble v) const { Size operator()(ldouble v) const {
if (v == 0) return 0; if (v == 0) return 0;
#ifdef __i386__ #ifdef __i386__
union { octa::ldouble v; struct { octa::Size h1, h2, h3, h4; }; } u; union { ldouble v; struct { Size h1, h2, h3, h4; }; } u;
u.h1 = u.h2 = u.h3 = u.h4 = 0; u.h1 = u.h2 = u.h3 = u.h4 = 0;
u.v = v; u.v = v;
return (u.h1 ^ u.h2 ^ u.h3 ^ u.h4); return (u.h1 ^ u.h2 ^ u.h3 ^ u.h4);
#else #else
#ifdef __x86_64__ #ifdef __x86_64__
union { octa::ldouble v; struct { octa::Size h1, h2; }; } u; union { ldouble v; struct { Size h1, h2; }; } u;
u.h1 = u.h2 = 0; u.h1 = u.h2 = 0;
u.v = v; u.v = v;
return (u.h1 ^ u.h2); return (u.h1 ^ u.h2);
#else #else
return octa::detail::ScalarHash<octa::ldouble>::operator()(v); return detail::ScalarHash<ldouble>::operator()(v);
#endif #endif
#endif #endif
} }
}; };
namespace detail { namespace detail {
template<typename T, bool = octa::IsSame<octa::RemoveConst<T>, char>::value> template<typename T, bool = IsSame<RemoveConst<T>, char>::value>
struct ToHashPtr { struct ToHashPtr {
using Argument = T *; using Argument = T *;
using Result = octa::Size; using Result = Size;
octa::Size operator()(T *v) const { Size operator()(T *v) const {
union { T *v; octa::Size h; } u; union { T *v; Size h; } u;
u.v = v; u.v = v;
return octa::detail::mem_hash((const void *)&u, sizeof(u)); return detail::mem_hash((const void *)&u, sizeof(u));
} }
}; };
template<typename T> struct ToHashPtr<T, true> { template<typename T> struct ToHashPtr<T, true> {
using Argument = T *; using Argument = T *;
using Result = octa::Size; using Result = Size;
octa::Size operator()(T *v) const { Size operator()(T *v) const {
return octa::detail::mem_hash(v, strlen(v)); return detail::mem_hash(v, strlen(v));
} }
}; };
} }
template<typename T> struct ToHash<T *>: octa::detail::ToHashPtr<T> {}; template<typename T> struct ToHash<T *>: detail::ToHashPtr<T> {};
template<typename T> template<typename T>
typename ToHash<T>::Result to_hash(const T &v) { typename ToHash<T>::Result to_hash(const T &v) {
@ -446,8 +446,8 @@ namespace detail {
} /* namespace detail */ } /* namespace detail */
template<typename R, typename T> template<typename R, typename T>
octa::detail::MemFn<R, T> mem_fn(R T:: *ptr) { detail::MemFn<R, T> mem_fn(R T:: *ptr) {
return octa::detail::MemFn<R, T>(ptr); return detail::MemFn<R, T>(ptr);
} }
/* function impl /* function impl
@ -465,7 +465,7 @@ namespace detail {
struct FunctorInPlace { struct FunctorInPlace {
static constexpr bool value = sizeof(T) <= sizeof(FunctorData) static constexpr bool value = sizeof(T) <= sizeof(FunctorData)
&& (alignof(FunctorData) % alignof(T)) == 0 && (alignof(FunctorData) % alignof(T)) == 0
&& octa::IsMoveConstructible<T>::value; && IsMoveConstructible<T>::value;
}; };
struct FunctionManager; struct FunctionManager;
@ -498,15 +498,15 @@ namespace detail {
struct FunctorDataManager { struct FunctorDataManager {
template<typename R, typename ...Args> template<typename R, typename ...Args>
static R call(const FunctorData &s, Args ...args) { static R call(const FunctorData &s, Args ...args) {
return ((T &)s)(octa::forward<Args>(args)...); return ((T &)s)(forward<Args>(args)...);
} }
static void store_f(FmStorage &s, T v) { static void store_f(FmStorage &s, T v) {
new (&get_ref(s)) T(octa::forward<T>(v)); new (&get_ref(s)) T(forward<T>(v));
} }
static void move_f(FmStorage &lhs, FmStorage &&rhs) { static void move_f(FmStorage &lhs, FmStorage &&rhs) {
new (&get_ref(lhs)) T(octa::move(get_ref(rhs))); new (&get_ref(lhs)) T(move(get_ref(rhs)));
} }
static void destroy_f(A &, FmStorage &s) { static void destroy_f(A &, FmStorage &s) {
@ -529,20 +529,18 @@ namespace detail {
> { > {
template<typename R, typename ...Args> template<typename R, typename ...Args>
static R call(const FunctorData &s, Args ...args) { static R call(const FunctorData &s, Args ...args) {
return (*(octa::AllocatorPointer<A> &)s) return (*(AllocatorPointer<A> &)s)(forward<Args>(args)...);
(octa::forward<Args>(args)...);
} }
static void store_f(FmStorage &s, T v) { static void store_f(FmStorage &s, T v) {
A &a = s.get_alloc<A>(); A &a = s.get_alloc<A>();
AllocatorPointer<A> *ptr = new (&get_ptr_ref(s)) AllocatorPointer<A> *ptr = new (&get_ptr_ref(s))
AllocatorPointer<A>(allocator_allocate(a, 1)); AllocatorPointer<A>(allocator_allocate(a, 1));
allocator_construct(a, *ptr, octa::forward<T>(v)); allocator_construct(a, *ptr, forward<T>(v));
} }
static void move_f(FmStorage &lhs, FmStorage &&rhs) { static void move_f(FmStorage &lhs, FmStorage &&rhs) {
new (&get_ptr_ref(lhs)) AllocatorPointer<A>(octa::move( new (&get_ptr_ref(lhs)) AllocatorPointer<A>(move(get_ptr_ref(rhs)));
get_ptr_ref(rhs)));
get_ptr_ref(rhs) = nullptr; get_ptr_ref(rhs) = nullptr;
} }
@ -572,7 +570,7 @@ namespace detail {
template<typename T, typename A> template<typename T, typename A>
static void create_fm(FmStorage &s, A &&a) { static void create_fm(FmStorage &s, A &&a) {
new (&s.get_alloc<A>()) A(octa::move(a)); new (&s.get_alloc<A>()) A(move(a));
s.manager = &get_default_fm<T, A>(); s.manager = &get_default_fm<T, A>();
} }
@ -599,9 +597,9 @@ namespace detail {
static void call_move_and_destroy(FmStorage &lhs, static void call_move_and_destroy(FmStorage &lhs,
FmStorage &&rhs) { FmStorage &&rhs) {
using Spec = FunctorDataManager<T, A>; using Spec = FunctorDataManager<T, A>;
Spec::move_f(lhs, octa::move(rhs)); Spec::move_f(lhs, move(rhs));
Spec::destroy_f(rhs.get_alloc<A>(), rhs); Spec::destroy_f(rhs.get_alloc<A>(), rhs);
create_fm<T, A>(lhs, octa::move(rhs.get_alloc<A>())); create_fm<T, A>(lhs, move(rhs.get_alloc<A>()));
rhs.get_alloc<A>().~A(); rhs.get_alloc<A>().~A();
} }
@ -665,7 +663,7 @@ namespace detail {
template<typename T> template<typename T>
T func_to_functor(T &&f) { T func_to_functor(T &&f) {
return octa::forward<T>(f); return forward<T>(f);
} }
template<typename RR, typename T, typename ...AA> template<typename RR, typename T, typename ...AA>
@ -685,24 +683,24 @@ namespace detail {
struct Nat {}; struct Nat {};
template<typename U> template<typename U>
static decltype(func_to_functor(octa::declval<U>()) static decltype(func_to_functor(declval<U>()) (declval<A>()...))
(octa::declval<A>()...)) test(U *); test(U *);
template<typename> template<typename>
static Nat test(...); static Nat test(...);
static constexpr bool value = octa::IsConvertible< static constexpr bool value = IsConvertible<
decltype(test<T>(nullptr)), R decltype(test<T>(nullptr)), R
>::value; >::value;
}; };
template<typename T> template<typename T>
using FunctorType = decltype(func_to_functor(octa::declval<T>())); using FunctorType = decltype(func_to_functor(declval<T>()));
} /* namespace detail */ } /* namespace detail */
template<typename R, typename ...Args> template<typename R, typename ...Args>
struct Function<R(Args...)>: octa::detail::FunctionBase<R, Args...> { struct Function<R(Args...)>: detail::FunctionBase<R, Args...> {
Function( ) { init_empty(); } Function( ) { init_empty(); }
Function(octa::Nullptr) { init_empty(); } Function(Nullptr) { init_empty(); }
Function(Function &&f) { Function(Function &&f) {
init_empty(); init_empty();
@ -713,45 +711,45 @@ struct Function<R(Args...)>: octa::detail::FunctionBase<R, Args...> {
f.p_stor.manager->call_copyf(p_stor, f.p_stor); f.p_stor.manager->call_copyf(p_stor, f.p_stor);
} }
template<typename T, typename = octa::EnableIf< template<typename T, typename = EnableIf<
octa::detail::IsValidFunctor<T, R(Args...)>::value detail::IsValidFunctor<T, R(Args...)>::value
>> Function(T f) { >> Function(T f) {
if (func_is_null(f)) { if (func_is_null(f)) {
init_empty(); init_empty();
return; return;
} }
initialize(octa::detail::func_to_functor(octa::forward<T>(f)), initialize(detail::func_to_functor(forward<T>(f)),
octa::Allocator<octa::detail::FunctorType<T>>()); Allocator<detail::FunctorType<T>>());
} }
template<typename A> template<typename A>
Function(octa::AllocatorArg, const A &) { init_empty(); } Function(AllocatorArg, const A &) { init_empty(); }
template<typename A> template<typename A>
Function(octa::AllocatorArg, const A &, octa::Nullptr) { init_empty(); } Function(AllocatorArg, const A &, Nullptr) { init_empty(); }
template<typename A> template<typename A>
Function(octa::AllocatorArg, const A &, Function &&f) { Function(AllocatorArg, const A &, Function &&f) {
init_empty(); init_empty();
swap(f); swap(f);
} }
template<typename A> template<typename A>
Function(octa::AllocatorArg, const A &a, const Function &f): Function(AllocatorArg, const A &a, const Function &f):
p_call(f.p_call) { p_call(f.p_call) {
const octa::detail::FunctionManager *mfa const detail::FunctionManager *mfa
= &octa::detail::get_default_fm<octa::AllocatorValue<A>, A>(); = &detail::get_default_fm<AllocatorValue<A>, A>();
if (f.p_stor.manager == mfa) { if (f.p_stor.manager == mfa) {
octa::detail::create_fm<octa::AllocatorValue<A>, A>(p_stor, A(a)); detail::create_fm<AllocatorValue<A>, A>(p_stor, A(a));
mfa->call_copyf_fo(p_stor, f.p_stor); mfa->call_copyf_fo(p_stor, f.p_stor);
return; return;
} }
using AA = AllocatorRebind<A, Function>; using AA = AllocatorRebind<A, Function>;
const octa::detail::FunctionManager *mff const detail::FunctionManager *mff
= &octa::detail::get_default_fm<Function, AA>(); = &detail::get_default_fm<Function, AA>();
if (f.p_stor.manager == mff) { if (f.p_stor.manager == mff) {
octa::detail::create_fm<Function, AA>(p_stor, AA(a)); detail::create_fm<Function, AA>(p_stor, AA(a));
mff->call_copyf_fo(p_stor, f.P_stor); mff->call_copyf_fo(p_stor, f.P_stor);
return; return;
} }
@ -759,14 +757,14 @@ struct Function<R(Args...)>: octa::detail::FunctionBase<R, Args...> {
initialize(f, AA(a)); initialize(f, AA(a));
} }
template<typename A, typename T, typename = octa::EnableIf< template<typename A, typename T, typename = EnableIf<
octa::detail::IsValidFunctor<T, R(Args...)>::value detail::IsValidFunctor<T, R(Args...)>::value
>> Function(octa::AllocatorArg, const A &a, T f) { >> Function(AllocatorArg, const A &a, T f) {
if (func_is_null(f)) { if (func_is_null(f)) {
init_empty(); init_empty();
return; return;
} }
initialize(octa::detail::func_to_functor(octa::forward<T>(f)), A(a)); initialize(detail::func_to_functor(forward<T>(f)), A(a));
} }
~Function() { ~Function() {
@ -786,45 +784,41 @@ struct Function<R(Args...)>: octa::detail::FunctionBase<R, Args...> {
}; };
R operator()(Args ...args) const { R operator()(Args ...args) const {
return p_call(p_stor.data, octa::forward<Args>(args)...); return p_call(p_stor.data, forward<Args>(args)...);
} }
template<typename F, typename A> template<typename F, typename A>
void assign(F &&f, const A &a) { void assign(F &&f, const A &a) {
Function(octa::allocator_arg, a, octa::forward<F>(f)).swap(*this); Function(allocator_arg, a, forward<F>(f)).swap(*this);
} }
void swap(Function &f) { void swap(Function &f) {
octa::detail::FmStorage tmp; detail::FmStorage tmp;
f.p_stor.manager->call_move_and_destroyf(tmp, f.p_stor.manager->call_move_and_destroyf(tmp, move(f.p_stor));
octa::move(f.p_stor)); p_stor.manager->call_move_and_destroyf(f.p_stor, move(p_stor));
p_stor.manager->call_move_and_destroyf(f.p_stor, tmp.manager->call_move_and_destroyf(p_stor, move(tmp));
octa::move(p_stor));
tmp.manager->call_move_and_destroyf(p_stor,
octa::move(tmp));
octa::swap(p_call, f.p_call); octa::swap(p_call, f.p_call);
} }
operator bool() const { return p_call != nullptr; } operator bool() const { return p_call != nullptr; }
private: private:
octa::detail::FmStorage p_stor; detail::FmStorage p_stor;
R (*p_call)(const octa::detail::FunctorData &, Args...); R (*p_call)(const detail::FunctorData &, Args...);
template<typename T, typename A> template<typename T, typename A>
void initialize(T &&f, A &&a) { void initialize(T &&f, A &&a) {
p_call = &octa::detail::FunctorDataManager<T, A>::template call<R, Args...>; p_call = &detail::FunctorDataManager<T, A>::template call<R, Args...>;
octa::detail::create_fm<T, A>(p_stor, octa::forward<A>(a)); detail::create_fm<T, A>(p_stor, forward<A>(a));
octa::detail::FunctorDataManager<T, A>::store_f(p_stor, detail::FunctorDataManager<T, A>::store_f(p_stor, forward<T>(f));
octa::forward<T>(f));
} }
void init_empty() { void init_empty() {
using emptyf = R(*)(Args...); using emptyf = R(*)(Args...);
using emptya = octa::Allocator<emptyf>; using emptya = Allocator<emptyf>;
p_call = nullptr; p_call = nullptr;
octa::detail::create_fm<emptyf, emptya>(p_stor, emptya()); detail::create_fm<emptyf, emptya>(p_stor, emptya());
octa::detail::FunctorDataManager<emptyf, emptya>::store_f(p_stor, detail::FunctorDataManager<emptyf, emptya>::store_f(p_stor,
nullptr); nullptr);
} }
@ -847,16 +841,16 @@ private:
}; };
template<typename T> template<typename T>
bool operator==(octa::Nullptr, const Function<T> &rhs) { return !rhs; } bool operator==(Nullptr, const Function<T> &rhs) { return !rhs; }
template<typename T> template<typename T>
bool operator==(const Function<T> &lhs, octa::Nullptr) { return !lhs; } bool operator==(const Function<T> &lhs, Nullptr) { return !lhs; }
template<typename T> template<typename T>
bool operator!=(octa::Nullptr, const Function<T> &rhs) { return rhs; } bool operator!=(Nullptr, const Function<T> &rhs) { return rhs; }
template<typename T> template<typename T>
bool operator!=(const Function<T> &lhs, octa::Nullptr) { return lhs; } bool operator!=(const Function<T> &lhs, Nullptr) { return lhs; }
namespace detail { namespace detail {
template<typename F> template<typename F>
@ -865,7 +859,7 @@ namespace detail {
template<typename C, typename R, typename ...A> template<typename C, typename R, typename ...A>
struct DcLambdaTypes<R (C::*)(A...) const> { struct DcLambdaTypes<R (C::*)(A...) const> {
using Ptr = R (*)(A...); using Ptr = R (*)(A...);
using Obj = octa::Function<R(A...)>; using Obj = Function<R(A...)>;
}; };
template<typename F> template<typename F>
@ -874,7 +868,7 @@ namespace detail {
static char test(typename DcLambdaTypes<FF>::Ptr); static char test(typename DcLambdaTypes<FF>::Ptr);
template<typename FF> template<typename FF>
static int test(...); static int test(...);
static constexpr bool value = (sizeof(test<F>(octa::declval<F>())) == 1); static constexpr bool value = (sizeof(test<F>(declval<F>())) == 1);
}; };
template<typename F, bool = DcFuncTest<F>::value> template<typename F, bool = DcFuncTest<F>::value>
@ -887,8 +881,8 @@ namespace detail {
using Type = typename DcLambdaTypes<F>::Ptr; using Type = typename DcLambdaTypes<F>::Ptr;
}; };
template<typename F, bool = octa::IsDefaultConstructible<F>::value && template<typename F, bool = IsDefaultConstructible<F>::value &&
octa::IsMoveConstructible<F>::value IsMoveConstructible<F>::value
> struct DcFuncTypeObj { > struct DcFuncTypeObj {
using Type = typename DcFuncTypeObjBase<F>::Type; using Type = typename DcFuncTypeObjBase<F>::Type;
}; };
@ -898,7 +892,7 @@ namespace detail {
using Type = F; using Type = F;
}; };
template<typename F, bool = octa::IsClass<F>::value> template<typename F, bool = IsClass<F>::value>
struct DcFuncType { struct DcFuncType {
using Type = F; using Type = F;
}; };
@ -910,7 +904,7 @@ namespace detail {
} }
template<typename F> using FunctionMakeDefaultConstructible template<typename F> using FunctionMakeDefaultConstructible
= typename octa::detail::DcFuncType<F>::Type; = typename detail::DcFuncType<F>::Type;
} /* namespace octa */ } /* namespace octa */

View File

@ -39,13 +39,13 @@ namespace octa {
template<typename T> using InitializerList = std::initializer_list<T>; template<typename T> using InitializerList = std::initializer_list<T>;
template<typename T> template<typename T>
octa::PointerRange<const T> iter(std::initializer_list<T> init) { PointerRange<const T> iter(std::initializer_list<T> init) {
return octa::PointerRange<const T>(init.begin(), init.end()); return PointerRange<const T>(init.begin(), init.end());
} }
template<typename T> template<typename T>
octa::PointerRange<const T> citer(std::initializer_list<T> init) { PointerRange<const T> citer(std::initializer_list<T> init) {
return octa::PointerRange<const T>(init.begin(), init.end()); return PointerRange<const T>(init.begin(), init.end());
} }
} }

View File

@ -24,15 +24,15 @@ namespace detail {
}; };
template<typename R> template<typename R>
static inline octa::Size estimate_hrsize(const R &range, static inline Size estimate_hrsize(const R &range,
octa::EnableIf<octa::IsFiniteRandomAccessRange<R>::value, bool> = true EnableIf<IsFiniteRandomAccessRange<R>::value, bool> = true
) { ) {
return range.size(); return range.size();
} }
template<typename R> template<typename R>
static inline octa::Size estimate_hrsize(const R &, static inline Size estimate_hrsize(const R &,
octa::EnableIf<!octa::IsFiniteRandomAccessRange<R>::value, bool> = true EnableIf<!IsFiniteRandomAccessRange<R>::value, bool> = true
) { ) {
/* we have no idea how big the range actually is */ /* we have no idea how big the range actually is */
return 16; return 16;
@ -40,12 +40,12 @@ namespace detail {
} }
template<typename T> template<typename T>
struct HashRange: octa::InputRange<HashRange<T>, octa::ForwardRangeTag, T> { struct HashRange: InputRange<HashRange<T>, ForwardRangeTag, T> {
private: private:
template<typename U> template<typename U>
friend struct HashRange; friend struct HashRange;
using Chain = octa::detail::HashChain<T>; using Chain = detail::HashChain<T>;
Chain **p_beg; Chain **p_beg;
Chain **p_end; Chain **p_end;
@ -57,7 +57,7 @@ private:
if (p_beg != p_end) p_node = p_beg[0]; if (p_beg != p_end) p_node = p_beg[0];
} }
public: public:
HashRange() = delete; HashRange(): p_beg(nullptr), p_end(nullptr), p_node(nullptr) {}
HashRange(const HashRange &v): p_beg(v.p_beg), p_end(v.p_end), HashRange(const HashRange &v): p_beg(v.p_beg), p_end(v.p_end),
p_node(v.p_node) {} p_node(v.p_node) {}
HashRange(Chain **beg, Chain **end): p_beg(beg), p_end(end), p_node() { HashRange(Chain **beg, Chain **end): p_beg(beg), p_end(end), p_node() {
@ -67,9 +67,9 @@ public:
p_node(node) {} p_node(node) {}
template<typename U> template<typename U>
HashRange(const HashRange<U> &v, octa::EnableIf< HashRange(const HashRange<U> &v, EnableIf<
octa::IsSame<RemoveCv<T>, RemoveCv<U>>::value && IsSame<RemoveCv<T>, RemoveCv<U>>::value &&
octa::IsConvertible<U *, T *>::value, bool IsConvertible<U *, T *>::value, bool
> = true): p_beg((Chain **)v.p_beg), p_end((Chain **)v.p_end), > = true): p_beg((Chain **)v.p_beg), p_end((Chain **)v.p_end),
p_node((Chain *)v.p_node) {} p_node((Chain *)v.p_node) {}
@ -99,22 +99,22 @@ public:
}; };
template<typename T> template<typename T>
struct BucketRange: octa::InputRange<BucketRange<T>, octa::ForwardRangeTag, T> { struct BucketRange: InputRange<BucketRange<T>, ForwardRangeTag, T> {
private: private:
template<typename U> template<typename U>
friend struct BucketRange; friend struct BucketRange;
using Chain = octa::detail::HashChain<T>; using Chain = detail::HashChain<T>;
Chain *p_node; Chain *p_node;
public: public:
BucketRange() = delete; BucketRange(): p_node(nullptr) {}
BucketRange(Chain *node): p_node(node) {} BucketRange(Chain *node): p_node(node) {}
BucketRange(const BucketRange &v): p_node(v.p_node) {} BucketRange(const BucketRange &v): p_node(v.p_node) {}
template<typename U> template<typename U>
BucketRange(const BucketRange<U> &v, octa::EnableIf< BucketRange(const BucketRange<U> &v, EnableIf<
octa::IsSame<RemoveCv<T>, RemoveCv<U>>::value && IsSame<RemoveCv<T>, RemoveCv<U>>::value &&
octa::IsConvertible<U *, T *>::value, bool IsConvertible<U *, T *>::value, bool
> = true): p_node((Chain *)v.p_node) {} > = true): p_node((Chain *)v.p_node) {}
BucketRange &operator=(const BucketRange &v) { BucketRange &operator=(const BucketRange &v) {
@ -149,51 +149,51 @@ namespace detail {
bool Multihash bool Multihash
> struct Hashtable { > struct Hashtable {
private: private:
static constexpr octa::Size CHUNKSIZE = 64; static constexpr Size CHUNKSIZE = 64;
using Chain = octa::detail::HashChain<E>; using Chain = detail::HashChain<E>;
struct Chunk { struct Chunk {
Chain chains[CHUNKSIZE]; Chain chains[CHUNKSIZE];
Chunk *next; Chunk *next;
}; };
octa::Size p_size; Size p_size;
octa::Size p_len; Size p_len;
Chunk *p_chunks; Chunk *p_chunks;
Chain *p_unused; Chain *p_unused;
using CPA = octa::AllocatorRebind<A, Chain *>; using CPA = AllocatorRebind<A, Chain *>;
using CHA = octa::AllocatorRebind<A, Chunk>; using CHA = AllocatorRebind<A, Chunk>;
using CoreAllocPair = octa::detail::CompressedPair<CPA, CHA>; using CoreAllocPair = detail::CompressedPair<CPA, CHA>;
using AllocPair = octa::detail::CompressedPair<A, CoreAllocPair>; using AllocPair = detail::CompressedPair<A, CoreAllocPair>;
using FuncPair = octa::detail::CompressedPair<H, C>; using FuncPair = detail::CompressedPair<H, C>;
using FAPair = octa::detail::CompressedPair<AllocPair, FuncPair>; using FAPair = detail::CompressedPair<AllocPair, FuncPair>;
using DataPair = octa::detail::CompressedPair<Chain **, FAPair>; using DataPair = detail::CompressedPair<Chain **, FAPair>;
using Range = octa::HashRange<E>; using Range = HashRange<E>;
using ConstRange = octa::HashRange<const E>; using ConstRange = HashRange<const E>;
using LocalRange = octa::BucketRange<E>; using LocalRange = BucketRange<E>;
using ConstLocalRange = octa::BucketRange<const E>; using ConstLocalRange = BucketRange<const E>;
DataPair p_data; DataPair p_data;
float p_maxlf; float p_maxlf;
Range iter_from(Chain *c, octa::Size h) { Range iter_from(Chain *c, Size h) {
return Range(p_data.first() + h + 1, return Range(p_data.first() + h + 1,
p_data.first() + bucket_count(), c); p_data.first() + bucket_count(), c);
} }
ConstRange iter_from(Chain *c, octa::Size h) const { ConstRange iter_from(Chain *c, Size h) const {
using RChain = octa::detail::HashChain<const E>; using RChain = detail::HashChain<const E>;
return ConstRange((RChain **)(p_data.first() + h + 1), return ConstRange((RChain **)(p_data.first() + h + 1),
(RChain **)(p_data.first() + bucket_count()), (RChain **)(p_data.first() + bucket_count()),
(RChain *)c); (RChain *)c);
} }
bool find(const K &key, octa::Size &h, Chain *&oc) const { bool find(const K &key, Size &h, Chain *&oc) const {
if (!p_size) return false; if (!p_size) return false;
h = get_hash()(key) & (p_size - 1); h = get_hash()(key) & (p_size - 1);
for (Chain *c = p_data.first()[h]; c; c = c->next) { for (Chain *c = p_data.first()[h]; c; c = c->next) {
@ -205,10 +205,10 @@ private:
return false; return false;
} }
Chain *insert(octa::Size h) { Chain *insert(Size h) {
if (!p_unused) { if (!p_unused) {
Chunk *chunk = octa::allocator_allocate(get_challoc(), 1); Chunk *chunk = allocator_allocate(get_challoc(), 1);
octa::allocator_construct(get_challoc(), chunk); allocator_construct(get_challoc(), chunk);
chunk->next = p_chunks; chunk->next = p_chunks;
p_chunks = chunk; p_chunks = chunk;
for (Size i = 0; i < (CHUNKSIZE - 1); ++i) for (Size i = 0; i < (CHUNKSIZE - 1); ++i)
@ -227,12 +227,12 @@ private:
void delete_chunks(Chunk *chunks) { void delete_chunks(Chunk *chunks) {
for (Chunk *nc; chunks; chunks = nc) { for (Chunk *nc; chunks; chunks = nc) {
nc = chunks->next; nc = chunks->next;
octa::allocator_destroy(get_challoc(), chunks); allocator_destroy(get_challoc(), chunks);
octa::allocator_deallocate(get_challoc(), chunks, 1); allocator_deallocate(get_challoc(), chunks, 1);
} }
} }
T *access_base(const K &key, octa::Size &h) const { T *access_base(const K &key, Size &h) const {
if (!p_size) return NULL; if (!p_size) return NULL;
h = get_hash()(key) & (p_size - 1); h = get_hash()(key) & (p_size - 1);
for (Chain *c = p_data.first()[h]; c; c = c->next) { for (Chain *c = p_data.first()[h]; c; c = c->next) {
@ -242,23 +242,23 @@ private:
return NULL; return NULL;
} }
void rehash_ahead(octa::Size n) { void rehash_ahead(Size n) {
if (!bucket_count()) if (!bucket_count())
reserve(n); reserve(n);
else if ((float(size() + n) / bucket_count()) > max_load_factor()) else if ((float(size() + n) / bucket_count()) > max_load_factor())
rehash(octa::Size((size() + 1) / max_load_factor()) * 2); rehash(Size((size() + 1) / max_load_factor()) * 2);
} }
protected: protected:
template<typename U> template<typename U>
T &insert(octa::Size h, U &&key) { T &insert(Size h, U &&key) {
Chain *c = insert(h); Chain *c = insert(h);
B::set_key(c->value, octa::forward<U>(key), get_alloc()); B::set_key(c->value, forward<U>(key), get_alloc());
return B::get_data(c->value); return B::get_data(c->value);
} }
T &access_or_insert(const K &key) { T &access_or_insert(const K &key) {
octa::Size h = 0; Size h = 0;
T *v = access_base(key, h); T *v = access_base(key, h);
if (v) return *v; if (v) return *v;
rehash_ahead(1); rehash_ahead(1);
@ -266,22 +266,22 @@ protected:
} }
T &access_or_insert(K &&key) { T &access_or_insert(K &&key) {
octa::Size h = 0; Size h = 0;
T *v = access_base(key, h); T *v = access_base(key, h);
if (v) return *v; if (v) return *v;
rehash_ahead(1); rehash_ahead(1);
return insert(h, octa::move(key)); return insert(h, move(key));
} }
T &access(const K &key) const { T &access(const K &key) const {
octa::Size h; Size h;
return *access_base(key, h); return *access_base(key, h);
} }
template<typename R> template<typename R>
void assign_range(R range) { void assign_range(R range) {
clear(); clear();
reserve_at_least(octa::detail::estimate_hrsize(range)); reserve_at_least(detail::estimate_hrsize(range));
for (; !range.empty(); range.pop_front()) for (; !range.empty(); range.pop_front())
emplace(range.front()); emplace(range.front());
rehash_up(); rehash_up();
@ -311,13 +311,13 @@ protected:
return p_data.second().first().second().second(); return p_data.second().first().second().second();
} }
Hashtable(octa::Size size, const H &hf, const C &eqf, const A &alloc): Hashtable(Size size, const H &hf, const C &eqf, const A &alloc):
p_size(size), p_len(0), p_chunks(nullptr), p_unused(nullptr), p_size(size), p_len(0), p_chunks(nullptr), p_unused(nullptr),
p_data(nullptr, FAPair(AllocPair(alloc, CoreAllocPair(alloc, alloc)), p_data(nullptr, FAPair(AllocPair(alloc, CoreAllocPair(alloc, alloc)),
FuncPair(hf, eqf))), FuncPair(hf, eqf))),
p_maxlf(1.0f) { p_maxlf(1.0f) {
if (!size) return; if (!size) return;
p_data.first() = octa::allocator_allocate(get_cpalloc(), size); p_data.first() = allocator_allocate(get_cpalloc(), size);
memset(p_data.first(), 0, size * sizeof(Chain *)); memset(p_data.first(), 0, size * sizeof(Chain *));
} }
@ -327,22 +327,22 @@ protected:
FuncPair(ht.get_hash(), ht.get_eq()))), FuncPair(ht.get_hash(), ht.get_eq()))),
p_maxlf(ht.p_maxlf) { p_maxlf(ht.p_maxlf) {
if (!p_size) return; if (!p_size) return;
p_data.first() = octa::allocator_allocate(get_cpalloc(), p_size); p_data.first() = allocator_allocate(get_cpalloc(), p_size);
memset(p_data.first(), 0, p_size * sizeof(Chain *)); memset(p_data.first(), 0, p_size * sizeof(Chain *));
Chain **och = ht.p_data.first(); Chain **och = ht.p_data.first();
for (octa::Size h = 0; h < p_size; ++h) { for (Size h = 0; h < p_size; ++h) {
Chain *oc = och[h]; Chain *oc = och[h];
for (; oc; oc = oc->next) { for (; oc; oc = oc->next) {
Chain *nc = insert(h); Chain *nc = insert(h);
octa::allocator_destroy(get_alloc(), &nc->value); allocator_destroy(get_alloc(), &nc->value);
octa::allocator_construct(get_alloc(), &nc->value, oc->value); allocator_construct(get_alloc(), &nc->value, oc->value);
} }
} }
} }
Hashtable(Hashtable &&ht): p_size(ht.p_size), p_len(ht.p_len), Hashtable(Hashtable &&ht): p_size(ht.p_size), p_len(ht.p_len),
p_chunks(ht.p_chunks), p_unused(ht.p_unused), p_chunks(ht.p_chunks), p_unused(ht.p_unused),
p_data(octa::move(ht.p_data)), p_maxlf(ht.p_maxlf) { p_data(move(ht.p_data)), p_maxlf(ht.p_maxlf) {
ht.p_size = ht.p_len = 0; ht.p_size = ht.p_len = 0;
ht.p_chunks = nullptr; ht.p_chunks = nullptr;
ht.p_unused = nullptr; ht.p_unused = nullptr;
@ -368,10 +368,10 @@ protected:
p_len = 0; p_len = 0;
p_chunks = nullptr; p_chunks = nullptr;
p_unused = nullptr; p_unused = nullptr;
p_data.first() = octa::allocator_allocate(get_cpalloc(), p_size); p_data.first() = allocator_allocate(get_cpalloc(), p_size);
memset(p_data.first(), 0, p_size * sizeof(Chain *)); memset(p_data.first(), 0, p_size * sizeof(Chain *));
Chain **och = ht.p_data.first(); Chain **och = ht.p_data.first();
for (octa::Size h = 0; h < p_size; ++h) { for (Size h = 0; h < p_size; ++h) {
Chain *oc = och[h]; Chain *oc = och[h];
for (; oc; oc = oc->next) { for (; oc; oc = oc->next) {
Chain *nc = insert(h); Chain *nc = insert(h);
@ -382,11 +382,11 @@ protected:
Hashtable &operator=(const Hashtable &ht) { Hashtable &operator=(const Hashtable &ht) {
clear(); clear();
if (octa::AllocatorPropagateOnContainerCopyAssignment<A>::value) { if (AllocatorPropagateOnContainerCopyAssignment<A>::value) {
if ((get_cpalloc() != ht.get_cpalloc()) && p_size) { if ((get_cpalloc() != ht.get_cpalloc()) && p_size) {
octa::allocator_deallocate(get_cpalloc(), allocator_deallocate(get_cpalloc(),
p_data.first(), p_size); p_data.first(), p_size);
p_data.first() = octa::allocator_allocate(get_cpalloc(), p_data.first() = allocator_allocate(get_cpalloc(),
p_size); p_size);
memset(p_data.first(), 0, p_size * sizeof(Chain *)); memset(p_data.first(), 0, p_size * sizeof(Chain *));
} }
@ -407,18 +407,18 @@ protected:
octa::swap(p_unused, ht.p_unused); octa::swap(p_unused, ht.p_unused);
octa::swap(p_data.first(), ht.p_data.first()); octa::swap(p_data.first(), ht.p_data.first());
octa::swap(p_data.second().second(), ht.p_data.second().second()); octa::swap(p_data.second().second(), ht.p_data.second().second());
if (octa::AllocatorPropagateOnContainerMoveAssignment<A>::value) if (AllocatorPropagateOnContainerMoveAssignment<A>::value)
octa::swap(p_data.second().first(), ht.p_data.second().first()); octa::swap(p_data.second().first(), ht.p_data.second().first());
return *this; return *this;
} }
void rehash_up() { void rehash_up() {
if (load_factor() <= max_load_factor()) return; if (load_factor() <= max_load_factor()) return;
rehash(octa::Size(size() / max_load_factor()) * 2); rehash(Size(size() / max_load_factor()) * 2);
} }
void reserve_at_least(octa::Size count) { void reserve_at_least(Size count) {
octa::Size nc = octa::Size(ceil(count / max_load_factor())); Size nc = Size(ceil(count / max_load_factor()));
if (p_size > nc) return; if (p_size > nc) return;
rehash(nc); rehash(nc);
} }
@ -430,13 +430,13 @@ protected:
octa::swap(p_unused, ht.p_unused); octa::swap(p_unused, ht.p_unused);
octa::swap(p_data.first(), ht.p_data.first()); octa::swap(p_data.first(), ht.p_data.first());
octa::swap(p_data.second().second(), ht.p_data.second().second()); octa::swap(p_data.second().second(), ht.p_data.second().second());
if (octa::AllocatorPropagateOnContainerSwap<A>::value) if (AllocatorPropagateOnContainerSwap<A>::value)
octa::swap(p_data.second().first(), ht.p_data.second().first()); octa::swap(p_data.second().first(), ht.p_data.second().first());
} }
public: public:
~Hashtable() { ~Hashtable() {
if (p_size) octa::allocator_deallocate(get_cpalloc(), if (p_size) allocator_deallocate(get_cpalloc(),
p_data.first(), p_size); p_data.first(), p_size);
delete_chunks(p_chunks); delete_chunks(p_chunks);
} }
@ -454,18 +454,18 @@ public:
} }
bool empty() const { return p_len == 0; } bool empty() const { return p_len == 0; }
octa::Size size() const { return p_len; } Size size() const { return p_len; }
Size max_size() const { return Size(~0) / sizeof(E); } Size max_size() const { return Size(~0) / sizeof(E); }
octa::Size bucket_count() const { return p_size; } Size bucket_count() const { return p_size; }
octa::Size max_bucket_count() const { return Size(~0) / sizeof(Chain); } Size max_bucket_count() const { return Size(~0) / sizeof(Chain); }
octa::Size bucket(const K &key) const { Size bucket(const K &key) const {
return get_hash()(key) & (p_size - 1); return get_hash()(key) & (p_size - 1);
} }
octa::Size bucket_size(octa::Size n) const { Size bucket_size(Size n) const {
octa::Size ret = 0; Size ret = 0;
if (ret >= p_size) return ret; if (ret >= p_size) return ret;
Chain *c = p_data.first()[n]; Chain *c = p_data.first()[n];
if (!c) return ret; if (!c) return ret;
@ -475,16 +475,16 @@ public:
} }
template<typename ...Args> template<typename ...Args>
octa::Pair<Range, bool> emplace(Args &&...args) { Pair<Range, bool> emplace(Args &&...args) {
rehash_ahead(1); rehash_ahead(1);
E elem(octa::forward<Args>(args)...); E elem(forward<Args>(args)...);
octa::Size h = get_hash()(B::get_key(elem)) & (p_size - 1); Size h = get_hash()(B::get_key(elem)) & (p_size - 1);
if (Multihash) { if (Multihash) {
/* multihash: always insert */ /* multihash: always insert */
Chain *ch = insert(h); Chain *ch = insert(h);
B::swap_elem(ch->value, elem); B::swap_elem(ch->value, elem);
Chain **hch = p_data.first(); Chain **hch = p_data.first();
return octa::make_pair(Range(hch + h + 1, hch + bucket_count(), return make_pair(Range(hch + h + 1, hch + bucket_count(),
ch), true); ch), true);
} }
Chain *found = nullptr; Chain *found = nullptr;
@ -501,14 +501,14 @@ public:
B::swap_elem(found->value, elem); B::swap_elem(found->value, elem);
} }
Chain **hch = p_data.first(); Chain **hch = p_data.first();
return octa::make_pair(Range(hch + h + 1, hch + bucket_count(), return make_pair(Range(hch + h + 1, hch + bucket_count(),
found), ins); found), ins);
} }
octa::Size erase(const K &key) { Size erase(const K &key) {
if (!p_len) return 0; if (!p_len) return 0;
octa::Size olen = p_len; Size olen = p_len;
octa::Size h = get_hash()(key) & (p_size - 1); Size h = get_hash()(key) & (p_size - 1);
Chain **p = &p_data.first()[h], *c = *p; Chain **p = &p_data.first()[h], *c = *p;
while (c) { while (c) {
if (get_eq()(key, B::get_key(c->value))) { if (get_eq()(key, B::get_key(c->value))) {
@ -516,8 +516,8 @@ public:
*p = c->next; *p = c->next;
c->next = p_unused; c->next = p_unused;
p_unused = c; p_unused = c;
octa::allocator_destroy(get_alloc(), &c->value); allocator_destroy(get_alloc(), &c->value);
octa::allocator_construct(get_alloc(), &c->value); allocator_construct(get_alloc(), &c->value);
if (!Multihash) return 1; if (!Multihash) return 1;
} else { } else {
p = &c->next; p = &c->next;
@ -527,10 +527,10 @@ public:
return olen - p_len; return olen - p_len;
} }
octa::Size count(const K &key) { Size count(const K &key) {
if (!p_len) return 0; if (!p_len) return 0;
octa::Size h = get_hash()(key) & (p_size - 1); Size h = get_hash()(key) & (p_size - 1);
octa::Size ret = 0; Size ret = 0;
for (Chain *c = p_data.first()[h]; c; c = c->next) for (Chain *c = p_data.first()[h]; c; c = c->next)
if (get_eq()(key, B::get_key(c->value))) { if (get_eq()(key, B::get_key(c->value))) {
++ret; ++ret;
@ -540,14 +540,14 @@ public:
} }
Range find(const K &key) { Range find(const K &key) {
octa::Size h = 0; Size h = 0;
Chain *c; Chain *c;
if (find(key, h, c)) return iter_from(c, h); if (find(key, h, c)) return iter_from(c, h);
return Range(); return Range();
} }
ConstRange find(const K &key) const { ConstRange find(const K &key) const {
octa::Size h = 0; Size h = 0;
Chain *c; Chain *c;
if (find(key, h, c)) return iter_from(c, h); if (find(key, h, c)) return iter_from(c, h);
return ConstRange(); return ConstRange();
@ -557,21 +557,21 @@ public:
float max_load_factor() const { return p_maxlf; } float max_load_factor() const { return p_maxlf; }
void max_load_factor(float lf) { p_maxlf = lf; } void max_load_factor(float lf) { p_maxlf = lf; }
void rehash(octa::Size count) { void rehash(Size count) {
octa::Size fbcount = octa::Size(p_len / max_load_factor()); Size fbcount = Size(p_len / max_load_factor());
if (fbcount > count) count = fbcount; if (fbcount > count) count = fbcount;
Chain **och = p_data.first(); Chain **och = p_data.first();
Chain **nch = octa::allocator_allocate(get_cpalloc(), count); Chain **nch = allocator_allocate(get_cpalloc(), count);
memset(nch, 0, count * sizeof(Chain *)); memset(nch, 0, count * sizeof(Chain *));
p_data.first() = nch; p_data.first() = nch;
octa::Size osize = p_size; Size osize = p_size;
p_size = count; p_size = count;
for (octa::Size i = 0; i < osize; ++i) { for (Size i = 0; i < osize; ++i) {
for (Chain *oc = och[i]; oc;) { for (Chain *oc = och[i]; oc;) {
octa::Size h = get_hash()(B::get_key(oc->value)) & (p_size - 1); Size h = get_hash()(B::get_key(oc->value)) & (p_size - 1);
Chain *nxc = oc->next; Chain *nxc = oc->next;
oc->next = nch[h]; oc->next = nch[h];
nch[h] = oc; nch[h] = oc;
@ -579,39 +579,39 @@ public:
} }
} }
if (och && osize) octa::allocator_deallocate(get_cpalloc(), if (och && osize) allocator_deallocate(get_cpalloc(),
och, osize); och, osize);
} }
void reserve(octa::Size count) { void reserve(Size count) {
rehash(octa::Size(ceil(count / max_load_factor()))); rehash(Size(ceil(count / max_load_factor())));
} }
Range iter() { Range iter() {
return Range(p_data.first(), p_data.first() + bucket_count()); return Range(p_data.first(), p_data.first() + bucket_count());
} }
ConstRange iter() const { ConstRange iter() const {
using Chain = octa::detail::HashChain<const E>; using Chain = detail::HashChain<const E>;
return ConstRange((Chain **)p_data.first(), return ConstRange((Chain **)p_data.first(),
(Chain **)(p_data.first() + bucket_count())); (Chain **)(p_data.first() + bucket_count()));
} }
ConstRange citer() const { ConstRange citer() const {
using Chain = octa::detail::HashChain<const E>; using Chain = detail::HashChain<const E>;
return ConstRange((Chain **)p_data.first(), return ConstRange((Chain **)p_data.first(),
(Chain **)(p_data.first() + bucket_count())); (Chain **)(p_data.first() + bucket_count()));
} }
LocalRange iter(octa::Size n) { LocalRange iter(Size n) {
if (n >= p_size) return LocalRange(); if (n >= p_size) return LocalRange();
return LocalRange(p_data.first()[n]); return LocalRange(p_data.first()[n]);
} }
ConstLocalRange iter(octa::Size n) const { ConstLocalRange iter(Size n) const {
using Chain = octa::detail::HashChain<const E>; using Chain = detail::HashChain<const E>;
if (n >= p_size) return ConstLocalRange(); if (n >= p_size) return ConstLocalRange();
return ConstLocalRange((Chain *)p_data.first()[n]); return ConstLocalRange((Chain *)p_data.first()[n]);
} }
ConstLocalRange citer(octa::Size n) const { ConstLocalRange citer(Size n) const {
using Chain = octa::detail::HashChain<const E>; using Chain = detail::HashChain<const E>;
if (n >= p_size) return ConstLocalRange(); if (n >= p_size) return ConstLocalRange();
return ConstLocalRange((Chain *)p_data.first()[n]); return ConstLocalRange((Chain *)p_data.first()[n]);
} }

View File

@ -39,7 +39,7 @@ struct FileStream: Stream {
} }
template<typename A> template<typename A>
FileStream(const octa::AnyString<A> &path, StreamMode mode): p_f() { FileStream(const AnyString<A> &path, StreamMode mode): p_f() {
open(path, mode); open(path, mode);
} }
@ -56,13 +56,13 @@ struct FileStream: Stream {
bool open(const char *path, StreamMode mode) { bool open(const char *path, StreamMode mode) {
if (p_f) return false; if (p_f) return false;
p_f = fopen(path, octa::detail::filemodes[octa::Size(mode)]); p_f = fopen(path, detail::filemodes[Size(mode)]);
p_owned = true; p_owned = true;
return is_open(); return is_open();
} }
template<typename A> template<typename A>
bool open(const octa::AnyString<A> &path, StreamMode mode) { bool open(const AnyString<A> &path, StreamMode mode) {
return open(path.data(), mode); return open(path.data(), mode);
} }
@ -104,11 +104,11 @@ struct FileStream: Stream {
bool flush() { return !fflush(p_f); } bool flush() { return !fflush(p_f); }
octa::Size read_bytes(void *buf, octa::Size count) { Size read_bytes(void *buf, Size count) {
return fread(buf, 1, count, p_f); return fread(buf, 1, count, p_f);
} }
octa::Size write_bytes(const void *buf, octa::Size count) { Size write_bytes(const void *buf, Size count) {
return fwrite(buf, 1, count, p_f); return fwrite(buf, 1, count, p_f);
} }
@ -147,46 +147,46 @@ static inline void write(const char *s) {
} }
template<typename A> template<typename A>
static inline void write(const octa::AnyString<A> &s) { static inline void write(const AnyString<A> &s) {
fwrite(s.data(), 1, s.size(), ::stdout); fwrite(s.data(), 1, s.size(), ::stdout);
} }
template<typename T> template<typename T>
static inline void write(const T &v) { static inline void write(const T &v) {
octa::write(octa::to_string(v)); write(octa::to_string(v));
} }
template<typename T, typename ...A> template<typename T, typename ...A>
static inline void write(const T &v, const A &...args) { static inline void write(const T &v, const A &...args) {
octa::write(v); write(v);
write(args...); write(args...);
} }
static inline void writeln(const char *s) { static inline void writeln(const char *s) {
octa::write(s); write(s);
putc('\n', ::stdout); putc('\n', ::stdout);
} }
template<typename A> template<typename A>
static inline void writeln(const octa::AnyString<A> &s) { static inline void writeln(const AnyString<A> &s) {
octa::write(s); write(s);
putc('\n', ::stdout); putc('\n', ::stdout);
} }
template<typename T> template<typename T>
static inline void writeln(const T &v) { static inline void writeln(const T &v) {
octa::writeln(octa::to_string(v)); writeln(octa::to_string(v));
} }
template<typename T, typename ...A> template<typename T, typename ...A>
static inline void writeln(const T &v, const A &...args) { static inline void writeln(const T &v, const A &...args) {
octa::write(v); write(v);
write(args...); write(args...);
putc('\n', ::stdout); putc('\n', ::stdout);
} }
namespace detail { namespace detail {
struct UnsafeWritefRange: octa::OutputRange<UnsafeWritefRange, char> { struct UnsafeWritefRange: OutputRange<UnsafeWritefRange, char> {
UnsafeWritefRange(char *p): p_ptr(p) {} UnsafeWritefRange(char *p): p_ptr(p) {}
bool put(char c) { bool put(char c) {
*p_ptr++ = c; *p_ptr++ = c;
@ -199,21 +199,21 @@ namespace detail {
template<typename ...A> template<typename ...A>
static inline void writef(const char *fmt, const A &...args) { static inline void writef(const char *fmt, const A &...args) {
char buf[512]; char buf[512];
octa::Ptrdiff need = octa::format(octa::detail::FormatOutRange< Ptrdiff need = format(detail::FormatOutRange<sizeof(buf)>(buf),
sizeof(buf)>(buf), fmt, args...); fmt, args...);
if (need < 0) return; if (need < 0) return;
else if (octa::Size(need) < sizeof(buf)) { else if (Size(need) < sizeof(buf)) {
fwrite(buf, 1, need, ::stdout); fwrite(buf, 1, need, ::stdout);
return; return;
} }
octa::Vector<char> s; Vector<char> s;
s.reserve(need); s.reserve(need);
octa::format(octa::detail::UnsafeWritefRange(s.data()), fmt, args...); format(detail::UnsafeWritefRange(s.data()), fmt, args...);
fwrite(s.data(), 1, need, ::stdout); fwrite(s.data(), 1, need, ::stdout);
} }
template<typename AL, typename ...A> template<typename AL, typename ...A>
static inline void writef(const octa::AnyString<AL> &fmt, static inline void writef(const AnyString<AL> &fmt,
const A &...args) { const A &...args) {
writef(fmt.data(), args...); writef(fmt.data(), args...);
} }
@ -225,7 +225,7 @@ static inline void writefln(const char *fmt, const A &...args) {
} }
template<typename AL, typename ...A> template<typename AL, typename ...A>
static inline void writefln(const octa::AnyString<AL> &fmt, static inline void writefln(const AnyString<AL> &fmt,
const A &...args) { const A &...args) {
writef(fmt, args...); writef(fmt, args...);
putc('\n', ::stdout); putc('\n', ::stdout);

View File

@ -18,7 +18,7 @@ namespace octa {
namespace detail { namespace detail {
template<typename K, typename T, typename A> struct MapBase { template<typename K, typename T, typename A> struct MapBase {
using Element = octa::Pair<const K, T>; using Element = Pair<const K, T>;
static inline const K &get_key(Element &e) { static inline const K &get_key(Element &e) {
return e.first; return e.first;
@ -28,9 +28,8 @@ namespace detail {
} }
template<typename U> template<typename U>
static inline void set_key(Element &e, U &&key, A &alloc) { static inline void set_key(Element &e, U &&key, A &alloc) {
octa::allocator_destroy(alloc, &e); allocator_destroy(alloc, &e);
octa::allocator_construct(alloc, &e, octa::forward<U>(key), allocator_construct(alloc, &e, forward<U>(key), move(T()));
octa::move(T()));
} }
static inline void swap_elem(Element &a, Element &b) { static inline void swap_elem(Element &a, Element &b) {
octa::swap(*((K *)&a.first), *((K *)&b.first)); octa::swap(*((K *)&a.first), *((K *)&b.first));
@ -41,59 +40,57 @@ namespace detail {
template< template<
typename K, typename T, typename H, typename K, typename T, typename H,
typename C, typename A, bool IsMultihash typename C, typename A, bool IsMultihash
> struct MapImpl: octa::detail::Hashtable< > struct MapImpl: detail::Hashtable<detail::MapBase<K, T, A>,
octa::detail::MapBase<K, T, A>, octa::Pair<const K, T>, Pair<const K, T>, K, T, H, C, A, IsMultihash
K, T, H, C, A, IsMultihash
> { > {
private: private:
using Base = octa::detail::Hashtable< using Base = detail::Hashtable<detail::MapBase<K, T, A>,
octa::detail::MapBase<K, T, A>, octa::Pair<const K, T>, Pair<const K, T>, K, T, H, C, A, IsMultihash
K, T, H, C, A, IsMultihash
>; >;
public: public:
using Key = K; using Key = K;
using Mapped = T; using Mapped = T;
using Size = octa::Size; using Size = Size;
using Difference = octa::Ptrdiff; using Difference = Ptrdiff;
using Hasher = H; using Hasher = H;
using KeyEqual = C; using KeyEqual = C;
using Value = octa::Pair<const K, T>; using Value = Pair<const K, T>;
using Reference = Value &; using Reference = Value &;
using Pointer = octa::AllocatorPointer<A>; using Pointer = AllocatorPointer<A>;
using ConstPointer = octa::AllocatorConstPointer<A>; using ConstPointer = AllocatorConstPointer<A>;
using Range = octa::HashRange<octa::Pair<const K, T>>; using Range = HashRange<Pair<const K, T>>;
using ConstRange = octa::HashRange<const octa::Pair<const K, T>>; using ConstRange = HashRange<const Pair<const K, T>>;
using LocalRange = octa::BucketRange<octa::Pair<const K, T>>; using LocalRange = BucketRange<Pair<const K, T>>;
using ConstLocalRange = octa::BucketRange<const octa::Pair<const K, T>>; using ConstLocalRange = BucketRange<const Pair<const K, T>>;
using Allocator = A; using Allocator = A;
explicit MapImpl(octa::Size size, const H &hf = H(), explicit MapImpl(Size size, const H &hf = H(),
const C &eqf = C(), const A &alloc = A() const C &eqf = C(), const A &alloc = A()
): Base(size, hf, eqf, alloc) {} ): Base(size, hf, eqf, alloc) {}
MapImpl(): MapImpl(0) {} MapImpl(): MapImpl(0) {}
explicit MapImpl(const A &alloc): MapImpl(0, H(), C(), alloc) {} explicit MapImpl(const A &alloc): MapImpl(0, H(), C(), alloc) {}
MapImpl(octa::Size size, const A &alloc): MapImpl(Size size, const A &alloc):
MapImpl(size, H(), C(), alloc) {} MapImpl(size, H(), C(), alloc) {}
MapImpl(octa::Size size, const H &hf, const A &alloc): MapImpl(Size size, const H &hf, const A &alloc):
MapImpl(size, hf, C(), alloc) {} MapImpl(size, hf, C(), alloc) {}
MapImpl(const MapImpl &m): Base(m, MapImpl(const MapImpl &m): Base(m,
octa::allocator_container_copy(m.get_alloc())) {} allocator_container_copy(m.get_alloc())) {}
MapImpl(const MapImpl &m, const A &alloc): Base(m, alloc) {} MapImpl(const MapImpl &m, const A &alloc): Base(m, alloc) {}
MapImpl(MapImpl &&m): Base(octa::move(m)) {} MapImpl(MapImpl &&m): Base(move(m)) {}
MapImpl(MapImpl &&m, const A &alloc): Base(octa::move(m), alloc) {} MapImpl(MapImpl &&m, const A &alloc): Base(move(m), alloc) {}
template<typename R, typename = octa::EnableIf< template<typename R, typename = EnableIf<
octa::IsInputRange<R>::value && IsInputRange<R>::value && IsConvertible<RangeReference<R>,
octa::IsConvertible<RangeReference<R>, Value>::value Value>::value
>> MapImpl(R range, octa::Size size = 0, const H &hf = H(), >> MapImpl(R range, Size size = 0, const H &hf = H(),
const C &eqf = C(), const A &alloc = A() const C &eqf = C(), const A &alloc = A()
): Base(size ? size : octa::detail::estimate_hrsize(range), ): Base(size ? size : detail::estimate_hrsize(range),
hf, eqf, alloc) { hf, eqf, alloc) {
for (; !range.empty(); range.pop_front()) for (; !range.empty(); range.pop_front())
Base::emplace(range.front()); Base::emplace(range.front());
@ -101,23 +98,23 @@ namespace detail {
} }
template<typename R> template<typename R>
MapImpl(R range, octa::Size size, const A &alloc) MapImpl(R range, Size size, const A &alloc)
: MapImpl(range, size, H(), C(), alloc) {} : MapImpl(range, size, H(), C(), alloc) {}
template<typename R> template<typename R>
MapImpl(R range, octa::Size size, const H &hf, const A &alloc) MapImpl(R range, Size size, const H &hf, const A &alloc)
: MapImpl(range, size, hf, C(), alloc) {} : MapImpl(range, size, hf, C(), alloc) {}
MapImpl(octa::InitializerList<Value> init, octa::Size size = 0, MapImpl(InitializerList<Value> init, Size size = 0,
const H &hf = H(), const C &eqf = C(), const A &alloc = A() const H &hf = H(), const C &eqf = C(), const A &alloc = A()
): MapImpl(octa::iter(init), size, hf, eqf, alloc) {} ): MapImpl(iter(init), size, hf, eqf, alloc) {}
MapImpl(octa::InitializerList<Value> init, octa::Size size, const A &alloc) MapImpl(InitializerList<Value> init, Size size, const A &alloc)
: MapImpl(octa::iter(init), size, H(), C(), alloc) {} : MapImpl(iter(init), size, H(), C(), alloc) {}
MapImpl(octa::InitializerList<Value> init, octa::Size size, const H &hf, MapImpl(InitializerList<Value> init, Size size, const H &hf,
const A &alloc const A &alloc
): MapImpl(octa::iter(init), size, hf, C(), alloc) {} ): MapImpl(iter(init), size, hf, C(), alloc) {}
MapImpl &operator=(const MapImpl &m) { MapImpl &operator=(const MapImpl &m) {
Base::operator=(m); Base::operator=(m);
@ -125,13 +122,13 @@ namespace detail {
} }
MapImpl &operator=(MapImpl &&m) { MapImpl &operator=(MapImpl &&m) {
Base::operator=(octa::move(m)); Base::operator=(move(m));
return *this; return *this;
} }
template<typename R, typename = octa::EnableIf< template<typename R, typename = EnableIf<
octa::IsInputRange<R>::value && IsInputRange<R>::value &&
octa::IsConvertible<RangeReference<R>, Value>::value IsConvertible<RangeReference<R>, Value>::value
>> MapImpl &operator=(R range) { >> MapImpl &operator=(R range) {
Base::assign_range(range); Base::assign_range(range);
return *this; return *this;
@ -157,7 +154,7 @@ namespace detail {
} }
T &operator[](K &&key) { T &operator[](K &&key) {
static_assert(!IsMultihash, "operator[] only allowed on regular maps"); static_assert(!IsMultihash, "operator[] only allowed on regular maps");
return Base::access_or_insert(octa::move(key)); return Base::access_or_insert(move(key));
} }
void swap(MapImpl &v) { void swap(MapImpl &v) {
@ -168,17 +165,17 @@ namespace detail {
template< template<
typename K, typename T, typename K, typename T,
typename H = octa::ToHash<K>, typename H = ToHash<K>,
typename C = octa::Equal<K>, typename C = Equal<K>,
typename A = octa::Allocator<octa::Pair<const K, T>> typename A = Allocator<Pair<const K, T>>
> using Map = octa::detail::MapImpl<K, T, H, C, A, false>; > using Map = detail::MapImpl<K, T, H, C, A, false>;
template< template<
typename K, typename T, typename K, typename T,
typename H = octa::ToHash<K>, typename H = ToHash<K>,
typename C = octa::Equal<K>, typename C = Equal<K>,
typename A = octa::Allocator<octa::Pair<const K, T>> typename A = Allocator<Pair<const K, T>>
> using Multimap = octa::detail::MapImpl<K, T, H, C, A, true>; > using Multimap = detail::MapImpl<K, T, H, C, A, true>;
} /* namespace octa */ } /* namespace octa */

View File

@ -24,7 +24,7 @@ struct Nothing {
constexpr Nothing nothing = Nothing(0); constexpr Nothing nothing = Nothing(0);
namespace detail { namespace detail {
template<typename T, bool = octa::IsTriviallyDestructible<T>::value> template<typename T, bool = IsTriviallyDestructible<T>::value>
class MaybeStorage { class MaybeStorage {
protected: protected:
using Value = T; using Value = T;
@ -37,19 +37,19 @@ namespace detail {
constexpr MaybeStorage(): p_null_state('\0') {} constexpr MaybeStorage(): p_null_state('\0') {}
MaybeStorage(const MaybeStorage &v): p_engaged(v.p_engaged) { MaybeStorage(const MaybeStorage &v): p_engaged(v.p_engaged) {
if (p_engaged) ::new(octa::address_of(p_value)) Value(v.p_value); if (p_engaged) ::new(address_of(p_value)) Value(v.p_value);
} }
MaybeStorage(MaybeStorage &&v): p_engaged(v.p_engaged) { MaybeStorage(MaybeStorage &&v): p_engaged(v.p_engaged) {
if (p_engaged) if (p_engaged)
::new(octa::address_of(p_value)) Value(octa::move(v.p_value)); ::new(address_of(p_value)) Value(move(v.p_value));
} }
constexpr MaybeStorage(const Value &v): p_value(v), p_engaged(true) {} constexpr MaybeStorage(const Value &v): p_value(v), p_engaged(true) {}
constexpr MaybeStorage(Value &&v): p_value(octa::move(v)), p_engaged(true) {} constexpr MaybeStorage(Value &&v): p_value(move(v)), p_engaged(true) {}
template<typename ...A> constexpr MaybeStorage(octa::InPlace, A &&...args): template<typename ...A> constexpr MaybeStorage(InPlace, A &&...args):
p_value(octa::forward<A>(args)...), p_engaged(true) {} p_value(forward<A>(args)...), p_engaged(true) {}
~MaybeStorage() { ~MaybeStorage() {
if (p_engaged) p_value.~Value(); if (p_engaged) p_value.~Value();
@ -69,58 +69,58 @@ namespace detail {
constexpr MaybeStorage(): p_null_state('\0') {} constexpr MaybeStorage(): p_null_state('\0') {}
MaybeStorage(const MaybeStorage &v): p_engaged(v.p_engaged) { MaybeStorage(const MaybeStorage &v): p_engaged(v.p_engaged) {
if (p_engaged) ::new(octa::address_of(p_value)) Value(v.p_value); if (p_engaged) ::new(address_of(p_value)) Value(v.p_value);
} }
MaybeStorage(MaybeStorage &&v): p_engaged(v.p_engaged) { MaybeStorage(MaybeStorage &&v): p_engaged(v.p_engaged) {
if (p_engaged) if (p_engaged)
::new(octa::address_of(p_value)) Value(octa::move(v.p_value)); ::new(address_of(p_value)) Value(move(v.p_value));
} }
constexpr MaybeStorage(const Value &v): p_value(v), p_engaged(true) {} constexpr MaybeStorage(const Value &v): p_value(v), p_engaged(true) {}
constexpr MaybeStorage(Value &&v): constexpr MaybeStorage(Value &&v):
p_value(octa::move(v)), p_engaged(true) {} p_value(move(v)), p_engaged(true) {}
template<typename ...A> template<typename ...A>
constexpr MaybeStorage(octa::InPlace, A &&...args): constexpr MaybeStorage(InPlace, A &&...args):
p_value(octa::forward<A>(args)...), p_engaged(true) {} p_value(forward<A>(args)...), p_engaged(true) {}
}; };
} }
template<typename T> template<typename T>
class Maybe: private octa::detail::MaybeStorage<T> { class Maybe: private detail::MaybeStorage<T> {
using Base = octa::detail::MaybeStorage<T>; using Base = detail::MaybeStorage<T>;
public: public:
using Value = T; using Value = T;
static_assert(!octa::IsReference<T>::value, static_assert(!IsReference<T>::value,
"Initialization of Maybe with a reference type is not allowed."); "Initialization of Maybe with a reference type is not allowed.");
static_assert(!octa::IsSame<octa::RemoveCv<T>, octa::InPlace>::value, static_assert(!IsSame<RemoveCv<T>, InPlace>::value,
"Initialization of Maybe with InPlace is not allowed."); "Initialization of Maybe with InPlace is not allowed.");
static_assert(!octa::IsSame<octa::RemoveCv<T>, octa::Nothing>::value, static_assert(!IsSame<RemoveCv<T>, Nothing>::value,
"Initialization of Maybe with Nothing is not allowed."); "Initialization of Maybe with Nothing is not allowed.");
static_assert(octa::IsObject<T>::value, static_assert(IsObject<T>::value,
"Initialization of Maybe with non-object type is not allowed."); "Initialization of Maybe with non-object type is not allowed.");
static_assert(octa::IsDestructible<T>::value, static_assert(IsDestructible<T>::value,
"Initialization of Maybe with a non-destructible object is not allowed."); "Initialization of Maybe with a non-destructible object is not allowed.");
constexpr Maybe() {} constexpr Maybe() {}
Maybe(const Maybe &) = default; Maybe(const Maybe &) = default;
Maybe(Maybe &&) = default; Maybe(Maybe &&) = default;
constexpr Maybe(octa::Nothing) {} constexpr Maybe(Nothing) {}
constexpr Maybe(const Value &v): Base(v) {} constexpr Maybe(const Value &v): Base(v) {}
constexpr Maybe(Value &&v): Base(octa::move(v)) {} constexpr Maybe(Value &&v): Base(move(v)) {}
template<typename ...A, typename = octa::EnableIf< template<typename ...A, typename = EnableIf<
octa::IsConstructible<T, A...>::value>> IsConstructible<T, A...>::value>>
constexpr explicit Maybe(octa::InPlace, A &&...args): Base(octa::in_place, constexpr explicit Maybe(InPlace, A &&...args): Base(in_place,
octa::forward<A>(args)...) {} forward<A>(args)...) {}
template<typename U, typename ...A, typename = typename octa::EnableIf< template<typename U, typename ...A, typename = typename EnableIf<
octa::IsConstructible<T, std::initializer_list<U> &, A...>::value>> IsConstructible<T, std::initializer_list<U> &, A...>::value>>
constexpr explicit constexpr explicit
Maybe(octa::InPlace, std::initializer_list<U> il, A &&...args): Maybe(InPlace, std::initializer_list<U> il, A &&...args):
Base(octa::in_place, il, octa::forward<A>(args)...) {} Base(in_place, il, forward<A>(args)...) {}
~Maybe() = default; ~Maybe() = default;
@ -139,7 +139,7 @@ public:
if (this->p_engaged) if (this->p_engaged)
this->p_value.~Value(); this->p_value.~Value();
else else
::new(octa::address_of(this->p_value)) Value(v.p_value); ::new(address_of(this->p_value)) Value(v.p_value);
this->p_engaged = v.p_engaged; this->p_engaged = v.p_engaged;
} }
return *this; return *this;
@ -147,60 +147,58 @@ public:
Maybe &operator=(Maybe &&v) { Maybe &operator=(Maybe &&v) {
if (this->p_engaged == v.p_engaged) { if (this->p_engaged == v.p_engaged) {
if (this->p_engaged) this->p_value = octa::move(v.p_value); if (this->p_engaged) this->p_value = move(v.p_value);
} else { } else {
if (this->p_engaged) if (this->p_engaged)
this->p_value.~Value(); this->p_value.~Value();
else { else {
::new(octa::address_of(this->p_value)) ::new(address_of(this->p_value)) Value(move(v.p_value));
Value(octa::move(v.p_value));
} }
this->p_engaged = v.p_engaged; this->p_engaged = v.p_engaged;
} }
return *this; return *this;
} }
template<typename U, typename = octa::EnableIf< template<typename U, typename = EnableIf<
octa::IsSame<octa::RemoveReference<U>, Value>::value && IsSame<RemoveReference<U>, Value>::value &&
octa::IsConstructible<Value, U>::value && IsConstructible<Value, U>::value &&
octa::IsAssignable<Value &, U>::value IsAssignable<Value &, U>::value
>> >>
Maybe &operator=(U &&v) { Maybe &operator=(U &&v) {
if (this->p_engaged) { if (this->p_engaged) {
this->p_value = octa::forward<U>(v); this->p_value = forward<U>(v);
} else { } else {
::new(octa::address_of(this->p_value)) Value(octa::forward<U>(v)); ::new(address_of(this->p_value)) Value(forward<U>(v));
this->p_engaged = true; this->p_engaged = true;
} }
return *this; return *this;
} }
template<typename ...A, typename = octa::EnableIf< template<typename ...A, typename = EnableIf<
octa::IsConstructible<Value, A...>::value IsConstructible<Value, A...>::value
>> >>
void emplace(A &&...args) { void emplace(A &&...args) {
*this = octa::nothing; *this = nothing;
::new(octa::address_of(this->p_value)) ::new(address_of(this->p_value)) Value(forward<A>(args)...);
Value(octa::forward<A>(args)...);
this->p_engaged = true; this->p_engaged = true;
} }
template<typename U, typename ...A, typename = octa::EnableIf< template<typename U, typename ...A, typename = EnableIf<
octa::IsConstructible<Value, std::initializer_list<U> &, A...>::value IsConstructible<Value, std::initializer_list<U> &, A...>::value
>> >>
void emplace(std::initializer_list<U> il, A &&...args) { void emplace(std::initializer_list<U> il, A &&...args) {
*this = octa::nothing; *this = nothing;
::new(octa::address_of(this->p_value)) ::new(address_of(this->p_value))
Value(il, octa::forward<A>(args)...); Value(il, forward<A>(args)...);
this->p_engaged = true; this->p_engaged = true;
} }
constexpr const Value *operator->() const { constexpr const Value *operator->() const {
return octa::address_of(this->p_value); return address_of(this->p_value);
} }
Value *operator->() { Value *operator->() {
return octa::address_of(this->p_value); return address_of(this->p_value);
} }
constexpr const Value &operator*() const { constexpr const Value &operator*() const {
@ -223,21 +221,21 @@ public:
template<typename U> template<typename U>
constexpr Value value_or(U &&v) const & { constexpr Value value_or(U &&v) const & {
static_assert(octa::IsCopyConstructible<Value>::value, static_assert(IsCopyConstructible<Value>::value,
"Maybe<T>::value_or: T must be copy constructible"); "Maybe<T>::value_or: T must be copy constructible");
static_assert(octa::IsConvertible<U, Value>::value, static_assert(IsConvertible<U, Value>::value,
"Maybe<T>::value_or: U must be convertible to T"); "Maybe<T>::value_or: U must be convertible to T");
return this->p_engaged ? this->p_value : Value(octa::forward<U>(v)); return this->p_engaged ? this->p_value : Value(forward<U>(v));
} }
template<typename U> template<typename U>
Value value_or(U &&v) && { Value value_or(U &&v) && {
static_assert(octa::IsMoveConstructible<Value>::value, static_assert(IsMoveConstructible<Value>::value,
"Maybe<T>::value_or: T must be copy constructible"); "Maybe<T>::value_or: T must be copy constructible");
static_assert(octa::IsConvertible<U, Value>::value, static_assert(IsConvertible<U, Value>::value,
"Maybe<T>::value_or: U must be convertible to T"); "Maybe<T>::value_or: U must be convertible to T");
return this->p_engaged ? octa::move(this->p_value) return this->p_engaged ? move(this->p_value)
: Value(octa::forward<U>(v)); : Value(forward<U>(v));
} }
void swap(Maybe &v) { void swap(Maybe &v) {
@ -245,19 +243,17 @@ public:
if (this->p_engaged) octa::swap(this->p_value, v.p_value); if (this->p_engaged) octa::swap(this->p_value, v.p_value);
} else { } else {
if (this->p_engaged) { if (this->p_engaged) {
::new(octa::address_of(v.p_value)) ::new(address_of(v.p_value)) Value(move(this->p_value));
Value(octa::move(this->p_value));
this->p_value.~Value(); this->p_value.~Value();
} else { } else {
::new(octa::address_of(this->p_value)) ::new(address_of(this->p_value)) Value(move(v.p_value));
Value(octa::move(v.p_value));
v.p_value.~Value(); v.p_value.~Value();
} }
octa::swap(this->p_engaged, v.p_engaged); octa::swap(this->p_engaged, v.p_engaged);
} }
} }
octa::Size to_hash() const { Size to_hash() const {
return this->p_engaged ? octa::ToHash<T>()(this->p_value) : 0; return this->p_engaged ? octa::ToHash<T>()(this->p_value) : 0;
} }
}; };
@ -380,12 +376,12 @@ static inline constexpr bool operator!=(const T &b, const Maybe<T> &a) {
template<typename T> template<typename T>
static inline constexpr bool operator<(const Maybe<T> &a, const T &b) { static inline constexpr bool operator<(const Maybe<T> &a, const T &b) {
return bool(a) ? octa::Less<T>()(*a, b) : true; return bool(a) ? Less<T>()(*a, b) : true;
} }
template<typename T> template<typename T>
static inline constexpr bool operator<(const T &b, const Maybe<T> &a) { static inline constexpr bool operator<(const T &b, const Maybe<T> &a) {
return bool(a) ? octa::Less<T>()(b, *a) : false; return bool(a) ? Less<T>()(b, *a) : false;
} }
template<typename T> template<typename T>
@ -421,8 +417,8 @@ static inline constexpr bool operator>=(const T &b, const Maybe<T> &a) {
/* make maybe */ /* make maybe */
template<typename T> template<typename T>
constexpr Maybe<octa::Decay<T>> make_maybe(T &&v) { constexpr Maybe<Decay<T>> make_maybe(T &&v) {
return Maybe<octa::Decay<T>>(octa::forward<T>(v)); return Maybe<Decay<T>>(forward<T>(v));
} }
} /* namespace octa */ } /* namespace octa */

View File

@ -68,7 +68,7 @@ namespace detail {
template<typename T, bool = HasDifference<T>::value> template<typename T, bool = HasDifference<T>::value>
struct PointerDifferenceBase { struct PointerDifferenceBase {
using Type = octa::Ptrdiff; using Type = Ptrdiff;
}; };
template<typename T> struct PointerDifferenceBase<T, true> { template<typename T> struct PointerDifferenceBase<T, true> {
@ -82,7 +82,7 @@ namespace detail {
template<typename T> template<typename T>
struct PointerDifferenceType<T *> { struct PointerDifferenceType<T *> {
using Type = octa::Ptrdiff; using Type = Ptrdiff;
}; };
template<typename T, typename U> template<typename T, typename U>
@ -135,16 +135,16 @@ namespace detail {
} /*namespace detail */ } /*namespace detail */
template<typename T> template<typename T>
using Pointer = typename octa::detail::PointerPointer<T>::Type; using Pointer = typename detail::PointerPointer<T>::Type;
template<typename T> template<typename T>
using PointerElement = typename octa::detail::PointerElementType<T>::Type; using PointerElement = typename detail::PointerElementType<T>::Type;
template<typename T> template<typename T>
using PointerDifference = typename octa::detail::PointerDifferenceType<T>::Type; using PointerDifference = typename detail::PointerDifferenceType<T>::Type;
template<typename T, typename U> template<typename T, typename U>
using PointerRebind = typename octa::detail::PointerRebindType<T, U>::Type; using PointerRebind = typename detail::PointerRebindType<T, U>::Type;
/* pointer to */ /* pointer to */
@ -153,8 +153,7 @@ namespace detail {
template<typename T> template<typename T>
struct PointerTo { struct PointerTo {
static T pointer_to(octa::Conditional< static T pointer_to(Conditional<IsVoid<PointerElement<T>>::value,
octa::IsVoid<PointerElement<T>>::value,
PointerToNat, PointerElement<T> PointerToNat, PointerElement<T>
> &r) { > &r) {
return T::pointer_to(r); return T::pointer_to(r);
@ -163,20 +162,19 @@ namespace detail {
template<typename T> template<typename T>
struct PointerTo<T *> { struct PointerTo<T *> {
static T pointer_to(octa::Conditional< static T pointer_to(Conditional<IsVoid<T>::value,
octa::IsVoid<T>::value, PointerToNat, T PointerToNat, T
> &r) { > &r) {
return octa::address_of(r); return address_of(r);
} }
}; };
} }
template<typename T> template<typename T>
static T pointer_to(octa::Conditional< static T pointer_to(Conditional<IsVoid<PointerElement<T>>::value,
octa::IsVoid<PointerElement<T>>::value, detail::PointerToNat, PointerElement<T>
octa::detail::PointerToNat, PointerElement<T>
> &r) { > &r) {
return octa::detail::PointerTo<T>::pointer_to(r); return detail::PointerTo<T>::pointer_to(r);
} }
/* default deleter */ /* default deleter */
@ -212,7 +210,7 @@ namespace detail {
template<typename T> template<typename T>
static char ptr_test(typename T::Pointer * = 0); static char ptr_test(typename T::Pointer * = 0);
template<typename T> struct HasPtr: octa::IntegralConstant<bool, template<typename T> struct HasPtr: IntegralConstant<bool,
(sizeof(ptr_test<T>(0)) == 1) (sizeof(ptr_test<T>(0)) == 1)
> {}; > {};
@ -226,7 +224,7 @@ namespace detail {
}; };
template<typename T, typename D> struct PointerType { template<typename T, typename D> struct PointerType {
using Type = typename PointerBase<T, octa::RemoveReference<D>>::Type; using Type = typename PointerBase<T, RemoveReference<D>>::Type;
}; };
} /* namespace detail */ } /* namespace detail */
@ -234,7 +232,7 @@ template<typename T, typename D = DefaultDelete<T>>
struct Box { struct Box {
using Element = T; using Element = T;
using Deleter = D; using Deleter = D;
using Pointer = typename octa::detail::PointerType<T, D>::Type; using Pointer = typename detail::PointerType<T, D>::Type;
private: private:
struct Nat { int x; }; struct Nat { int x; };
@ -244,63 +242,63 @@ private:
public: public:
constexpr Box(): p_stor(nullptr, D()) { constexpr Box(): p_stor(nullptr, D()) {
static_assert(!octa::IsPointer<D>::value, static_assert(!IsPointer<D>::value,
"Box constructed with null fptr deleter"); "Box constructed with null fptr deleter");
} }
constexpr Box(octa::Nullptr): p_stor(nullptr, D()) { constexpr Box(Nullptr): p_stor(nullptr, D()) {
static_assert(!octa::IsPointer<D>::value, static_assert(!IsPointer<D>::value,
"Box constructed with null fptr deleter"); "Box constructed with null fptr deleter");
} }
explicit Box(Pointer p): p_stor(p, D()) { explicit Box(Pointer p): p_stor(p, D()) {
static_assert(!octa::IsPointer<D>::value, static_assert(!IsPointer<D>::value,
"Box constructed with null fptr deleter"); "Box constructed with null fptr deleter");
} }
Box(Pointer p, octa::Conditional<octa::IsReference<D>::value, Box(Pointer p, Conditional<IsReference<D>::value,
D, octa::AddLvalueReference<const D> D, AddLvalueReference<const D>
> d): p_stor(p, d) {} > d): p_stor(p, d) {}
Box(Pointer p, octa::RemoveReference<D> &&d): Box(Pointer p, RemoveReference<D> &&d):
p_stor(p, octa::move(d)) { p_stor(p, move(d)) {
static_assert(!octa::IsReference<D>::value, static_assert(!IsReference<D>::value,
"rvalue deleter cannot be a ref"); "rvalue deleter cannot be a ref");
} }
Box(Box &&u): p_stor(u.release(), octa::forward<D>(u.get_deleter())) {} Box(Box &&u): p_stor(u.release(), forward<D>(u.get_deleter())) {}
template<typename TT, typename DD> template<typename TT, typename DD>
Box(Box<TT, DD> &&u, octa::EnableIf<!octa::IsArray<TT>::value Box(Box<TT, DD> &&u, EnableIf<!IsArray<TT>::value
&& octa::IsConvertible<typename Box<TT, DD>::Pointer, Pointer>::value && IsConvertible<typename Box<TT, DD>::Pointer, Pointer>::value
&& octa::IsConvertible<DD, D>::value && IsConvertible<DD, D>::value
&& (!octa::IsReference<D>::value || octa::IsSame<D, DD>::value) && (!IsReference<D>::value || IsSame<D, DD>::value)
> = Nat()): p_stor(u.release(), octa::forward<DD>(u.get_deleter())) {} > = Nat()): p_stor(u.release(), forward<DD>(u.get_deleter())) {}
Box &operator=(Box &&u) { Box &operator=(Box &&u) {
reset(u.release()); reset(u.release());
p_stor.second() = octa::forward<D>(u.get_deleter()); p_stor.second() = forward<D>(u.get_deleter());
return *this; return *this;
} }
template<typename TT, typename DD> template<typename TT, typename DD>
EnableIf<!octa::IsArray<TT>::value EnableIf<!IsArray<TT>::value
&& octa::IsConvertible<typename Box<TT, DD>::Pointer, Pointer>::value && IsConvertible<typename Box<TT, DD>::Pointer, Pointer>::value
&& octa::IsAssignable<D &, DD &&>::value, && IsAssignable<D &, DD &&>::value,
Box & Box &
> operator=(Box<TT, DD> &&u) { > operator=(Box<TT, DD> &&u) {
reset(u.release()); reset(u.release());
p_stor.second() = octa::forward<DD>(u.get_deleter()); p_stor.second() = forward<DD>(u.get_deleter());
return *this; return *this;
} }
Box &operator=(octa::Nullptr) { Box &operator=(Nullptr) {
reset(); reset();
return *this; return *this;
} }
~Box() { reset(); } ~Box() { reset(); }
octa::AddLvalueReference<T> operator*() const { return *p_stor.first(); } AddLvalueReference<T> operator*() const { return *p_stor.first(); }
Pointer operator->() const { return p_stor.first(); } Pointer operator->() const { return p_stor.first(); }
explicit operator bool() const { explicit operator bool() const {
@ -329,31 +327,31 @@ public:
} }
private: private:
octa::detail::CompressedPair<T *, D> p_stor; detail::CompressedPair<T *, D> p_stor;
}; };
namespace detail { namespace detail {
template<typename T, typename U, bool = octa::IsSame< template<typename T, typename U, bool = IsSame<
octa::RemoveCv<PointerElement<T>>, RemoveCv<PointerElement<T>>,
octa::RemoveCv<PointerElement<U>> RemoveCv<PointerElement<U>>
>::value> struct SameOrLessCvQualifiedBase: octa::IsConvertible<T, U> {}; >::value> struct SameOrLessCvQualifiedBase: IsConvertible<T, U> {};
template<typename T, typename U> template<typename T, typename U>
struct SameOrLessCvQualifiedBase<T, U, false>: octa::False {}; struct SameOrLessCvQualifiedBase<T, U, false>: False {};
template<typename T, typename U, bool = octa::IsPointer<T>::value template<typename T, typename U, bool = IsPointer<T>::value
|| octa::IsSame<T, U>::value || octa::detail::HasElement<T>::value || IsSame<T, U>::value || detail::HasElement<T>::value
> struct SameOrLessCvQualified: SameOrLessCvQualifiedBase<T, U> {}; > struct SameOrLessCvQualified: SameOrLessCvQualifiedBase<T, U> {};
template<typename T, typename U> template<typename T, typename U>
struct SameOrLessCvQualified<T, U, false>: octa::False {}; struct SameOrLessCvQualified<T, U, false>: False {};
} /* namespace detail */ } /* namespace detail */
template<typename T, typename D> template<typename T, typename D>
struct Box<T[], D> { struct Box<T[], D> {
using Element = T; using Element = T;
using Deleter = D; using Deleter = D;
using Pointer = typename octa::detail::PointerType<T, D>::Type; using Pointer = typename detail::PointerType<T, D>::Type;
private: private:
struct Nat { int x; }; struct Nat { int x; };
@ -363,82 +361,82 @@ private:
public: public:
constexpr Box(): p_stor(nullptr, D()) { constexpr Box(): p_stor(nullptr, D()) {
static_assert(!octa::IsPointer<D>::value, static_assert(!IsPointer<D>::value,
"Box constructed with null fptr deleter"); "Box constructed with null fptr deleter");
} }
constexpr Box(octa::Nullptr): p_stor(nullptr, D()) { constexpr Box(Nullptr): p_stor(nullptr, D()) {
static_assert(!octa::IsPointer<D>::value, static_assert(!IsPointer<D>::value,
"Box constructed with null fptr deleter"); "Box constructed with null fptr deleter");
} }
template<typename U> explicit Box(U p, octa::EnableIf< template<typename U> explicit Box(U p, EnableIf<
octa::detail::SameOrLessCvQualified<U, Pointer>::value, Nat detail::SameOrLessCvQualified<U, Pointer>::value, Nat
> = Nat()): p_stor(p, D()) { > = Nat()): p_stor(p, D()) {
static_assert(!octa::IsPointer<D>::value, static_assert(!IsPointer<D>::value,
"Box constructed with null fptr deleter"); "Box constructed with null fptr deleter");
} }
template<typename U> Box(U p, octa::Conditional< template<typename U> Box(U p, Conditional<
octa::IsReference<D>::value, IsReference<D>::value,
D, AddLvalueReference<const D> D, AddLvalueReference<const D>
> d, octa::EnableIf<octa::detail::SameOrLessCvQualified<U, Pointer>::value, > d, EnableIf<detail::SameOrLessCvQualified<U, Pointer>::value,
Nat> = Nat()): p_stor(p, d) {} Nat> = Nat()): p_stor(p, d) {}
Box(octa::Nullptr, octa::Conditional<octa::IsReference<D>::value, Box(Nullptr, Conditional<IsReference<D>::value,
D, AddLvalueReference<const D> D, AddLvalueReference<const D>
> d): p_stor(nullptr, d) {} > d): p_stor(nullptr, d) {}
template<typename U> Box(U p, octa::RemoveReference<D> &&d, template<typename U> Box(U p, RemoveReference<D> &&d,
octa::EnableIf< EnableIf<
octa::detail::SameOrLessCvQualified<U, Pointer>::value, Nat detail::SameOrLessCvQualified<U, Pointer>::value, Nat
> = Nat()): p_stor(p, octa::move(d)) { > = Nat()): p_stor(p, move(d)) {
static_assert(!octa::IsReference<D>::value, static_assert(!IsReference<D>::value,
"rvalue deleter cannot be a ref"); "rvalue deleter cannot be a ref");
} }
Box(octa::Nullptr, octa::RemoveReference<D> &&d): Box(Nullptr, RemoveReference<D> &&d):
p_stor(nullptr, octa::move(d)) { p_stor(nullptr, move(d)) {
static_assert(!octa::IsReference<D>::value, static_assert(!IsReference<D>::value,
"rvalue deleter cannot be a ref"); "rvalue deleter cannot be a ref");
} }
Box(Box &&u): p_stor(u.release(), octa::forward<D>(u.get_deleter())) {} Box(Box &&u): p_stor(u.release(), forward<D>(u.get_deleter())) {}
template<typename TT, typename DD> template<typename TT, typename DD>
Box(Box<TT, DD> &&u, EnableIf<IsArray<TT>::value Box(Box<TT, DD> &&u, EnableIf<IsArray<TT>::value
&& octa::detail::SameOrLessCvQualified<typename Box<TT, DD>::Pointer, && detail::SameOrLessCvQualified<typename Box<TT, DD>::Pointer,
Pointer>::value Pointer>::value
&& octa::IsConvertible<DD, D>::value && IsConvertible<DD, D>::value
&& (!octa::IsReference<D>::value || && (!IsReference<D>::value ||
octa::IsSame<D, DD>::value)> = Nat() IsSame<D, DD>::value)> = Nat()
): p_stor(u.release(), octa::forward<DD>(u.get_deleter())) {} ): p_stor(u.release(), forward<DD>(u.get_deleter())) {}
Box &operator=(Box &&u) { Box &operator=(Box &&u) {
reset(u.release()); reset(u.release());
p_stor.second() = octa::forward<D>(u.get_deleter()); p_stor.second() = forward<D>(u.get_deleter());
return *this; return *this;
} }
template<typename TT, typename DD> template<typename TT, typename DD>
EnableIf<octa::IsArray<TT>::value EnableIf<IsArray<TT>::value
&& octa::detail::SameOrLessCvQualified<typename Box<TT, DD>::Pointer, && detail::SameOrLessCvQualified<typename Box<TT, DD>::Pointer,
Pointer>::value Pointer>::value
&& IsAssignable<D &, DD &&>::value, && IsAssignable<D &, DD &&>::value,
Box & Box &
> operator=(Box<TT, DD> &&u) { > operator=(Box<TT, DD> &&u) {
reset(u.release()); reset(u.release());
p_stor.second() = octa::forward<DD>(u.get_deleter()); p_stor.second() = forward<DD>(u.get_deleter());
return *this; return *this;
} }
Box &operator=(octa::Nullptr) { Box &operator=(Nullptr) {
reset(); reset();
return *this; return *this;
} }
~Box() { reset(); } ~Box() { reset(); }
octa::AddLvalueReference<T> operator[](octa::Size idx) const { AddLvalueReference<T> operator[](Size idx) const {
return p_stor.first()[idx]; return p_stor.first()[idx];
} }
@ -458,14 +456,14 @@ public:
} }
template<typename U> EnableIf< template<typename U> EnableIf<
octa::detail::SameOrLessCvQualified<U, Pointer>::value, void detail::SameOrLessCvQualified<U, Pointer>::value, void
> reset(U p) { > reset(U p) {
Pointer tmp = p_stor.first(); Pointer tmp = p_stor.first();
p_stor.first() = p; p_stor.first() = p;
if (tmp) p_stor.second()(tmp); if (tmp) p_stor.second()(tmp);
} }
void reset(octa::Nullptr) { void reset(Nullptr) {
Pointer tmp = p_stor.first(); Pointer tmp = p_stor.first();
p_stor.first() = nullptr; p_stor.first() = nullptr;
if (tmp) p_stor.second()(tmp); if (tmp) p_stor.second()(tmp);
@ -480,35 +478,35 @@ public:
} }
private: private:
octa::detail::CompressedPair<T *, D> p_stor; detail::CompressedPair<T *, D> p_stor;
}; };
namespace detail { namespace detail {
template<typename T> struct BoxIf { template<typename T> struct BoxIf {
using Box = octa::Box<T>; using Box = Box<T>;
}; };
template<typename T> struct BoxIf<T[]> { template<typename T> struct BoxIf<T[]> {
using BoxUnknownSize = octa::Box<T[]>; using BoxUnknownSize = Box<T[]>;
}; };
template<typename T, octa::Size N> struct BoxIf<T[N]> { template<typename T, Size N> struct BoxIf<T[N]> {
using BoxKnownSize = void; using BoxKnownSize = void;
}; };
} }
template<typename T, typename ...A> template<typename T, typename ...A>
typename octa::detail::BoxIf<T>::Box make_box(A &&...args) { typename detail::BoxIf<T>::Box make_box(A &&...args) {
return Box<T>(new T(octa::forward<A>(args)...)); return Box<T>(new T(forward<A>(args)...));
} }
template<typename T> template<typename T>
typename octa::detail::BoxIf<T>::BoxUnknownSize make_box(octa::Size n) { typename detail::BoxIf<T>::BoxUnknownSize make_box(Size n) {
return Box<T>(new octa::RemoveExtent<T>[n]()); return Box<T>(new RemoveExtent<T>[n]());
} }
template<typename T, typename ...A> template<typename T, typename ...A>
typename octa::detail::BoxIf<T>::BoxKnownSize make_box(A &&...args) = delete; typename detail::BoxIf<T>::BoxKnownSize make_box(A &&...args) = delete;
/* allocator */ /* allocator */
@ -531,8 +529,8 @@ template<> struct Allocator<const void> {
}; };
template<typename T> struct Allocator { template<typename T> struct Allocator {
using Size = octa::Size; using Size = Size;
using Difference = octa::Ptrdiff; using Difference = Ptrdiff;
using Value = T; using Value = T;
using Reference = T &; using Reference = T &;
using ConstReference = const T &; using ConstReference = const T &;
@ -554,22 +552,22 @@ template<typename T> struct Allocator {
Size max_size() const { return Size(~0) / sizeof(T); } Size max_size() const { return Size(~0) / sizeof(T); }
Pointer allocate(Size n, Allocator<void>::ConstPointer = nullptr) { Pointer allocate(Size n, Allocator<void>::ConstPointer = nullptr) {
return (Pointer) ::new octa::byte[n * sizeof(T)]; return (Pointer) ::new byte[n * sizeof(T)];
} }
void deallocate(Pointer p, Size) { ::delete[] (octa::byte *) p; } void deallocate(Pointer p, Size) { ::delete[] (byte *) p; }
template<typename U, typename ...A> template<typename U, typename ...A>
void construct(U *p, A &&...args) { void construct(U *p, A &&...args) {
::new((void *)p) U(octa::forward<A>(args)...); ::new((void *)p) U(forward<A>(args)...);
} }
void destroy(Pointer p) { p->~T(); } void destroy(Pointer p) { p->~T(); }
}; };
template<typename T> struct Allocator<const T> { template<typename T> struct Allocator<const T> {
using Size = octa::Size; using Size = Size;
using Difference = octa::Ptrdiff; using Difference = Ptrdiff;
using Value = const T; using Value = const T;
using Reference = const T &; using Reference = const T &;
using ConstReference = const T &; using ConstReference = const T &;
@ -588,14 +586,14 @@ template<typename T> struct Allocator<const T> {
Size max_size() const { return Size(~0) / sizeof(T); } Size max_size() const { return Size(~0) / sizeof(T); }
Pointer allocate(Size n, Allocator<void>::ConstPointer = nullptr) { Pointer allocate(Size n, Allocator<void>::ConstPointer = nullptr) {
return (Pointer) ::new octa::byte[n * sizeof(T)]; return (Pointer) ::new byte[n * sizeof(T)];
} }
void deallocate(Pointer p, Size) { ::delete[] (octa::byte *) p; } void deallocate(Pointer p, Size) { ::delete[] (byte *) p; }
template<typename U, typename ...A> template<typename U, typename ...A>
void construct(U *p, A &&...args) { void construct(U *p, A &&...args) {
::new((void *)p) U(octa::forward<A>(args)...); ::new((void *)p) U(forward<A>(args)...);
} }
void destroy(Pointer p) { p->~T(); } void destroy(Pointer p) { p->~T(); }
@ -678,7 +676,7 @@ namespace detail {
template<typename A, typename D, bool = SizeTest<A>::value> template<typename A, typename D, bool = SizeTest<A>::value>
struct SizeBase { struct SizeBase {
using Type = octa::MakeUnsigned<D>; using Type = MakeUnsigned<D>;
}; };
template<typename A, typename D> template<typename A, typename D>
@ -696,22 +694,22 @@ template<typename A>
using AllocatorValue = typename AllocatorType<A>::Value; using AllocatorValue = typename AllocatorType<A>::Value;
template<typename A> template<typename A>
using AllocatorPointer = typename octa::detail::PointerType< using AllocatorPointer = typename detail::PointerType<
AllocatorValue<A>, AllocatorType<A> AllocatorValue<A>, AllocatorType<A>
>::Type; >::Type;
template<typename A> template<typename A>
using AllocatorConstPointer = typename octa::detail::ConstPointer< using AllocatorConstPointer = typename detail::ConstPointer<
AllocatorValue<A>, AllocatorPointer<A>, AllocatorType<A> AllocatorValue<A>, AllocatorPointer<A>, AllocatorType<A>
>::Type; >::Type;
template<typename A> template<typename A>
using AllocatorVoidPointer = typename octa::detail::VoidPointer< using AllocatorVoidPointer = typename detail::VoidPointer<
AllocatorPointer<A>, AllocatorType<A> AllocatorPointer<A>, AllocatorType<A>
>::Type; >::Type;
template<typename A> template<typename A>
using AllocatorConstVoidPointer = typename octa::detail::ConstVoidPointer< using AllocatorConstVoidPointer = typename detail::ConstVoidPointer<
AllocatorPointer<A>, AllocatorType<A> AllocatorPointer<A>, AllocatorType<A>
>::Type; >::Type;
@ -737,21 +735,21 @@ namespace detail {
} }
template<typename A> template<typename A>
using AllocatorDifference = typename octa::detail::AllocDifference< using AllocatorDifference = typename detail::AllocDifference<
A, AllocatorPointer<A> A, AllocatorPointer<A>
>::Type; >::Type;
/* allocator size */ /* allocator size */
template<typename A> template<typename A>
using AllocatorSize = typename octa::detail::SizeBase< using AllocatorSize = typename detail::SizeBase<
A, AllocatorDifference<A> A, AllocatorDifference<A>
>::Type; >::Type;
/* allocator rebind */ /* allocator rebind */
namespace detail { namespace detail {
template<typename T, typename U, bool = octa::detail::HasRebind<T, U>::value> template<typename T, typename U, bool = detail::HasRebind<T, U>::value>
struct AllocTraitsRebindType { struct AllocTraitsRebindType {
using Type = typename T::template Rebind<U>; using Type = typename T::template Rebind<U>;
}; };
@ -772,7 +770,7 @@ namespace detail {
} /* namespace detail */ } /* namespace detail */
template<typename A, typename T> template<typename A, typename T>
using AllocatorRebind = typename octa::detail::AllocTraitsRebindType< using AllocatorRebind = typename detail::AllocTraitsRebindType<
AllocatorType<A>, T AllocatorType<A>, T
>::Type; >::Type;
@ -790,7 +788,7 @@ namespace detail {
template<typename A, bool = PropagateOnContainerCopyAssignmentTest< template<typename A, bool = PropagateOnContainerCopyAssignmentTest<
A A
>::value> struct PropagateOnContainerCopyAssignmentBase { >::value> struct PropagateOnContainerCopyAssignmentBase {
using Type = octa::False; using Type = False;
}; };
template<typename A> template<typename A>
@ -801,7 +799,7 @@ namespace detail {
template<typename A> template<typename A>
using AllocatorPropagateOnContainerCopyAssignment using AllocatorPropagateOnContainerCopyAssignment
= typename octa::detail::PropagateOnContainerCopyAssignmentBase<A>::Type; = typename detail::PropagateOnContainerCopyAssignmentBase<A>::Type;
/* allocator propagate on container move assignment */ /* allocator propagate on container move assignment */
@ -817,7 +815,7 @@ namespace detail {
template<typename A, bool = PropagateOnContainerMoveAssignmentTest< template<typename A, bool = PropagateOnContainerMoveAssignmentTest<
A A
>::value> struct PropagateOnContainerMoveAssignmentBase { >::value> struct PropagateOnContainerMoveAssignmentBase {
using Type = octa::False; using Type = False;
}; };
template<typename A> template<typename A>
@ -828,7 +826,7 @@ namespace detail {
template<typename A> template<typename A>
using AllocatorPropagateOnContainerMoveAssignment using AllocatorPropagateOnContainerMoveAssignment
= typename octa::detail::PropagateOnContainerMoveAssignmentBase<A>::Type; = typename detail::PropagateOnContainerMoveAssignmentBase<A>::Type;
/* allocator propagate on container swap */ /* allocator propagate on container swap */
@ -843,7 +841,7 @@ namespace detail {
template<typename A, bool = PropagateOnContainerSwapTest<A>::value> template<typename A, bool = PropagateOnContainerSwapTest<A>::value>
struct PropagateOnContainerSwapBase { struct PropagateOnContainerSwapBase {
using Type = octa::False; using Type = False;
}; };
template<typename A> template<typename A>
@ -854,7 +852,7 @@ namespace detail {
template<typename A> template<typename A>
using AllocatorPropagateOnContainerSwap using AllocatorPropagateOnContainerSwap
= typename octa::detail::PropagateOnContainerSwapBase<A>::Type; = typename detail::PropagateOnContainerSwapBase<A>::Type;
/* allocator is always equal */ /* allocator is always equal */
@ -868,7 +866,7 @@ namespace detail {
template<typename A, bool = IsAlwaysEqualTest<A>::value> template<typename A, bool = IsAlwaysEqualTest<A>::value>
struct IsAlwaysEqualBase { struct IsAlwaysEqualBase {
using Type = typename octa::IsEmpty<A>::Type; using Type = typename IsEmpty<A>::Type;
}; };
template<typename A> template<typename A>
@ -878,7 +876,7 @@ namespace detail {
} /* namespace detail */ } /* namespace detail */
template<typename A> template<typename A>
using AllocatorIsAlwaysEqual = typename octa::detail::IsAlwaysEqualBase<A>::Type; using AllocatorIsAlwaysEqual = typename detail::IsAlwaysEqualBase<A>::Type;
/* allocator allocate */ /* allocator allocate */
@ -891,33 +889,31 @@ allocator_allocate(A &a, AllocatorSize<A> n) {
namespace detail { namespace detail {
template<typename A, typename S, typename CVP> template<typename A, typename S, typename CVP>
auto allocate_hint_test(A &&a, S &&sz, CVP &&p) auto allocate_hint_test(A &&a, S &&sz, CVP &&p)
-> decltype(a.allocate(sz, p), octa::True()); -> decltype(a.allocate(sz, p), True());
template<typename A, typename S, typename CVP> template<typename A, typename S, typename CVP>
auto allocate_hint_test(const A &, S &&, CVP &&) auto allocate_hint_test(const A &, S &&, CVP &&)
-> octa::False; -> False;
template<typename A, typename S, typename CVP> template<typename A, typename S, typename CVP>
struct AllocateHintTest: octa::IntegralConstant<bool, struct AllocateHintTest: IntegralConstant<bool,
octa::IsSame< IsSame<decltype(allocate_hint_test(declval<A>(),
decltype(allocate_hint_test(octa::declval<A>(), declval<S>(),
octa::declval<S>(), declval<CVP>())), True
octa::declval<CVP>())),
octa::True
>::value >::value
> {}; > {};
template<typename A> template<typename A>
inline AllocatorPointer<A> allocate(A &a, AllocatorSize<A> n, inline AllocatorPointer<A> allocate(A &a, AllocatorSize<A> n,
AllocatorConstVoidPointer<A> h, AllocatorConstVoidPointer<A> h,
octa::True) { True) {
return a.allocate(n, h); return a.allocate(n, h);
} }
template<typename A> template<typename A>
inline AllocatorPointer<A> allocate(A &a, AllocatorSize<A> n, inline AllocatorPointer<A> allocate(A &a, AllocatorSize<A> n,
AllocatorConstVoidPointer<A>, AllocatorConstVoidPointer<A>,
octa::False) { False) {
return a.allocate(n); return a.allocate(n);
} }
} /* namespace detail */ } /* namespace detail */
@ -926,8 +922,8 @@ template<typename A>
inline AllocatorPointer<A> inline AllocatorPointer<A>
allocator_allocate(A &a, AllocatorSize<A> n, allocator_allocate(A &a, AllocatorSize<A> n,
AllocatorConstVoidPointer<A> h) { AllocatorConstVoidPointer<A> h) {
return octa::detail::allocate(a, n, h, return detail::allocate(a, n, h,
octa::detail::AllocateHintTest< detail::AllocateHintTest<
A, AllocatorSize<A>, AllocatorConstVoidPointer<A> A, AllocatorSize<A>, AllocatorConstVoidPointer<A>
>()); >());
} }
@ -945,139 +941,129 @@ inline void allocator_deallocate(A &a, AllocatorPointer<A> p,
namespace detail { namespace detail {
template<typename A, typename T, typename ...Args> template<typename A, typename T, typename ...Args>
auto construct_test(A &&a, T *p, Args &&...args) auto construct_test(A &&a, T *p, Args &&...args)
-> decltype(a.construct(p, octa::forward<Args>(args)...), -> decltype(a.construct(p, forward<Args>(args)...),
octa::True()); True());
template<typename A, typename T, typename ...Args> template<typename A, typename T, typename ...Args>
auto construct_test(const A &, T *, Args &&...) auto construct_test(const A &, T *, Args &&...)
-> octa::False; -> False;
template<typename A, typename T, typename ...Args> template<typename A, typename T, typename ...Args>
struct ConstructTest: octa::IntegralConstant<bool, struct ConstructTest: IntegralConstant<bool,
octa::IsSame< IsSame< decltype(construct_test(declval<A>(),
decltype(construct_test(octa::declval<A>(), declval<T>(),
octa::declval<T>(), declval<Args>()...)), True
octa::declval<Args>()...)),
octa::True
>::value >::value
> {}; > {};
template<typename A, typename T, typename ...Args> template<typename A, typename T, typename ...Args>
inline void construct(octa::True, A &a, T *p, Args &&...args) { inline void construct(True, A &a, T *p, Args &&...args) {
a.construct(p, octa::forward<Args>(args)...); a.construct(p, forward<Args>(args)...);
} }
template<typename A, typename T, typename ...Args> template<typename A, typename T, typename ...Args>
inline void construct(octa::False, A &, T *p, Args &&...args) { inline void construct(False, A &, T *p, Args &&...args) {
::new ((void *)p) T(octa::forward<Args>(args)...); ::new ((void *)p) T(forward<Args>(args)...);
} }
} /* namespace detail */ } /* namespace detail */
template<typename A, typename T, typename ...Args> template<typename A, typename T, typename ...Args>
inline void allocator_construct(A &a, T *p, Args &&...args) { inline void allocator_construct(A &a, T *p, Args &&...args) {
octa::detail::construct(octa::detail::ConstructTest< detail::construct(detail::ConstructTest<A, T *, Args...>(), a, p,
A, T *, Args... forward<Args>(args)...);
>(), a, p, octa::forward<Args>(args)...);
} }
/* allocator destroy */ /* allocator destroy */
namespace detail { namespace detail {
template<typename A, typename P> template<typename A, typename P>
auto destroy_test(A &&a, P &&p) -> decltype(a.destroy(p), octa::True()); auto destroy_test(A &&a, P &&p) -> decltype(a.destroy(p), True());
template<typename A, typename P> template<typename A, typename P>
auto destroy_test(const A &, P &&) -> octa::False; auto destroy_test(const A &, P &&) -> False;
template<typename A, typename P> template<typename A, typename P>
struct DestroyTest: octa::IntegralConstant<bool, struct DestroyTest: IntegralConstant<bool,
octa::IsSame< IsSame<decltype(destroy_test(declval<A>(), declval<P>())), True
decltype(destroy_test(octa::declval<A>(), octa::declval<P>())),
octa::True
>::value >::value
> {}; > {};
template<typename A, typename T> template<typename A, typename T>
inline void destroy(octa::True, A &a, T *p) { inline void destroy(True, A &a, T *p) {
a.destroy(p); a.destroy(p);
} }
template<typename A, typename T> template<typename A, typename T>
inline void destroy(octa::False, A &, T *p) { inline void destroy(False, A &, T *p) {
p->~T(); p->~T();
} }
} /* namespace detail */ } /* namespace detail */
template<typename A, typename T> template<typename A, typename T>
inline void allocator_destroy(A &a, T *p) { inline void allocator_destroy(A &a, T *p) {
octa::detail::destroy(octa::detail::DestroyTest<A, T *>(), a, p); detail::destroy(detail::DestroyTest<A, T *>(), a, p);
} }
/* allocator max size */ /* allocator max size */
namespace detail { namespace detail {
template<typename A> template<typename A>
auto alloc_max_size_test(A &&a) -> decltype(a.max_size(), octa::True()); auto alloc_max_size_test(A &&a) -> decltype(a.max_size(), True());
template<typename A> template<typename A>
auto alloc_max_size_test(const A &) -> octa::False; auto alloc_max_size_test(const A &) -> False;
template<typename A> template<typename A>
struct AllocMaxSizeTest: octa::IntegralConstant<bool, struct AllocMaxSizeTest: IntegralConstant<bool,
octa::IsSame< IsSame<decltype(alloc_max_size_test(declval<A &>())), True
decltype(alloc_max_size_test(octa::declval<A &>())),
octa::True
>::value >::value
> {}; > {};
template<typename A> template<typename A>
inline AllocatorSize<A> alloc_max_size(octa::True, const A &a) { inline AllocatorSize<A> alloc_max_size(True, const A &a) {
return a.max_size(); return a.max_size();
} }
template<typename A> template<typename A>
inline AllocatorSize<A> alloc_max_size(octa::False, const A &) { inline AllocatorSize<A> alloc_max_size(False, const A &) {
return AllocatorSize<A>(~0); return AllocatorSize<A>(~0);
} }
} /* namespace detail */ } /* namespace detail */
template<typename A> template<typename A>
inline AllocatorSize<A> allocator_max_size(const A &a) { inline AllocatorSize<A> allocator_max_size(const A &a) {
return octa::detail::alloc_max_size(octa::detail::AllocMaxSizeTest< return detail::alloc_max_size(detail::AllocMaxSizeTest<const A>(), a);
const A
>(), a);
} }
/* allocator container copy */ /* allocator container copy */
namespace detail { namespace detail {
template<typename A> template<typename A>
auto alloc_copy_test(A &&a) -> decltype(a.container_copy(), octa::True()); auto alloc_copy_test(A &&a) -> decltype(a.container_copy(), True());
template<typename A> template<typename A>
auto alloc_copy_test(const A &) -> octa::False; auto alloc_copy_test(const A &) -> False;
template<typename A> template<typename A>
struct AllocCopyTest: octa::IntegralConstant<bool, struct AllocCopyTest: IntegralConstant<bool,
octa::IsSame< IsSame<decltype(alloc_copy_test(declval<A &>())), True
decltype(alloc_copy_test(octa::declval<A &>())), octa::True
>::value >::value
> {}; > {};
template<typename A> template<typename A>
inline AllocatorType<A> alloc_container_copy(octa::True, const A &a) { inline AllocatorType<A> alloc_container_copy(True, const A &a) {
return a.container_copy(); return a.container_copy();
} }
template<typename A> template<typename A>
inline AllocatorType<A> alloc_container_copy(octa::False, const A &a) { inline AllocatorType<A> alloc_container_copy(False, const A &a) {
return a; return a;
} }
} /* namespace detail */ } /* namespace detail */
template<typename A> template<typename A>
inline AllocatorType<A> allocator_container_copy(const A &a) { inline AllocatorType<A> allocator_container_copy(const A &a) {
return octa::detail::alloc_container_copy(octa::detail::AllocCopyTest< return detail::alloc_container_copy(detail::AllocCopyTest<
const A const A
>(), a); >(), a);
} }

View File

@ -41,7 +41,7 @@ namespace detail { \
}; \ }; \
} \ } \
template<typename T> \ template<typename T> \
using Range##Name = typename octa::detail::Range##Name##Base<T>::Type; using Range##Name = typename detail::Range##Name##Base<T>::Type;
OCTA_RANGE_TRAIT(Category) OCTA_RANGE_TRAIT(Category)
OCTA_RANGE_TRAIT(Size) OCTA_RANGE_TRAIT(Size)
@ -70,7 +70,7 @@ namespace detail {
// is input range // is input range
namespace detail { namespace detail {
template<typename T, bool = octa::IsConvertible< template<typename T, bool = IsConvertible<
RangeCategory<T>, InputRangeTag RangeCategory<T>, InputRangeTag
>::value> struct IsInputRangeBase: False {}; >::value> struct IsInputRangeBase: False {};
@ -78,16 +78,16 @@ namespace detail {
struct IsInputRangeBase<T, true>: True {}; struct IsInputRangeBase<T, true>: True {};
} }
template<typename T, bool = octa::detail::IsRangeTest<T>::value> template<typename T, bool = detail::IsRangeTest<T>::value>
struct IsInputRange: False {}; struct IsInputRange: False {};
template<typename T> template<typename T>
struct IsInputRange<T, true>: octa::detail::IsInputRangeBase<T>::Type {}; struct IsInputRange<T, true>: detail::IsInputRangeBase<T>::Type {};
// is forward range // is forward range
namespace detail { namespace detail {
template<typename T, bool = octa::IsConvertible< template<typename T, bool = IsConvertible<
RangeCategory<T>, ForwardRangeTag RangeCategory<T>, ForwardRangeTag
>::value> struct IsForwardRangeBase: False {}; >::value> struct IsForwardRangeBase: False {};
@ -95,16 +95,16 @@ namespace detail {
struct IsForwardRangeBase<T, true>: True {}; struct IsForwardRangeBase<T, true>: True {};
} }
template<typename T, bool = octa::detail::IsRangeTest<T>::value> template<typename T, bool = detail::IsRangeTest<T>::value>
struct IsForwardRange: False {}; struct IsForwardRange: False {};
template<typename T> template<typename T>
struct IsForwardRange<T, true>: octa::detail::IsForwardRangeBase<T>::Type {}; struct IsForwardRange<T, true>: detail::IsForwardRangeBase<T>::Type {};
// is bidirectional range // is bidirectional range
namespace detail { namespace detail {
template<typename T, bool = octa::IsConvertible< template<typename T, bool = IsConvertible<
RangeCategory<T>, BidirectionalRangeTag RangeCategory<T>, BidirectionalRangeTag
>::value> struct IsBidirectionalRangeBase: False {}; >::value> struct IsBidirectionalRangeBase: False {};
@ -112,17 +112,17 @@ namespace detail {
struct IsBidirectionalRangeBase<T, true>: True {}; struct IsBidirectionalRangeBase<T, true>: True {};
} }
template<typename T, bool = octa::detail::IsRangeTest<T>::value> template<typename T, bool = detail::IsRangeTest<T>::value>
struct IsBidirectionalRange: False {}; struct IsBidirectionalRange: False {};
template<typename T> template<typename T>
struct IsBidirectionalRange<T, true>: struct IsBidirectionalRange<T, true>:
octa::detail::IsBidirectionalRangeBase<T>::Type {}; detail::IsBidirectionalRangeBase<T>::Type {};
// is random access range // is random access range
namespace detail { namespace detail {
template<typename T, bool = octa::IsConvertible< template<typename T, bool = IsConvertible<
RangeCategory<T>, RandomAccessRangeTag RangeCategory<T>, RandomAccessRangeTag
>::value> struct IsRandomAccessRangeBase: False {}; >::value> struct IsRandomAccessRangeBase: False {};
@ -130,17 +130,17 @@ namespace detail {
struct IsRandomAccessRangeBase<T, true>: True {}; struct IsRandomAccessRangeBase<T, true>: True {};
} }
template<typename T, bool = octa::detail::IsRangeTest<T>::value> template<typename T, bool = detail::IsRangeTest<T>::value>
struct IsRandomAccessRange: False {}; struct IsRandomAccessRange: False {};
template<typename T> template<typename T>
struct IsRandomAccessRange<T, true>: struct IsRandomAccessRange<T, true>:
octa::detail::IsRandomAccessRangeBase<T>::Type {}; detail::IsRandomAccessRangeBase<T>::Type {};
// is finite random access range // is finite random access range
namespace detail { namespace detail {
template<typename T, bool = octa::IsConvertible< template<typename T, bool = IsConvertible<
RangeCategory<T>, FiniteRandomAccessRangeTag RangeCategory<T>, FiniteRandomAccessRangeTag
>::value> struct IsFiniteRandomAccessRangeBase: False {}; >::value> struct IsFiniteRandomAccessRangeBase: False {};
@ -148,12 +148,12 @@ namespace detail {
struct IsFiniteRandomAccessRangeBase<T, true>: True {}; struct IsFiniteRandomAccessRangeBase<T, true>: True {};
} }
template<typename T, bool = octa::detail::IsRangeTest<T>::value> template<typename T, bool = detail::IsRangeTest<T>::value>
struct IsFiniteRandomAccessRange: False {}; struct IsFiniteRandomAccessRange: False {};
template<typename T> template<typename T>
struct IsFiniteRandomAccessRange<T, true>: struct IsFiniteRandomAccessRange<T, true>:
octa::detail::IsFiniteRandomAccessRangeBase<T>::Type {}; detail::IsFiniteRandomAccessRangeBase<T>::Type {};
// is infinite random access range // is infinite random access range
@ -174,12 +174,12 @@ namespace detail {
}; };
} }
template<typename T, bool = (octa::IsConvertible< template<typename T, bool = (IsConvertible<
RangeCategory<T>, OutputRangeTag RangeCategory<T>, OutputRangeTag
>::value || (IsInputRange<T>::value && >::value || (IsInputRange<T>::value &&
(octa::detail::OutputRangeTest<T, const RangeValue<T> &>::value || (detail::OutputRangeTest<T, const RangeValue<T> &>::value ||
octa::detail::OutputRangeTest<T, RangeValue<T> &&>::value || detail::OutputRangeTest<T, RangeValue<T> &&>::value ||
octa::detail::OutputRangeTest<T, RangeValue<T> >::value) detail::OutputRangeTest<T, RangeValue<T> >::value)
))> struct IsOutputRange: False {}; ))> struct IsOutputRange: False {};
template<typename T> template<typename T>
@ -195,7 +195,7 @@ namespace detail {
::new(&get_ref()) T(range); ::new(&get_ref()) T(range);
} }
explicit RangeIterator(T &&range) { explicit RangeIterator(T &&range) {
::new(&get_ref()) T(octa::move(range)); ::new(&get_ref()) T(move(range));
} }
RangeIterator &operator++() { RangeIterator &operator++() {
get_ref().pop_front(); get_ref().pop_front();
@ -208,7 +208,7 @@ namespace detail {
private: private:
T &get_ref() { return *((T *)&p_range); } T &get_ref() { return *((T *)&p_range); }
const T &get_ref() const { return *((T *)&p_range); } const T &get_ref() const { return *((T *)&p_range); }
octa::AlignedStorage<sizeof(T), alignof(T)> p_range; AlignedStorage<sizeof(T), alignof(T)> p_range;
}; };
} }
@ -259,12 +259,12 @@ public:
RangeHalf() = delete; RangeHalf() = delete;
RangeHalf(const T &range): p_range(range) {} RangeHalf(const T &range): p_range(range) {}
template<typename U, typename = octa::EnableIf< template<typename U, typename = EnableIf<
octa::IsConvertible<U, T>::value IsConvertible<U, T>::value
>> RangeHalf(const RangeHalf<U> &half): p_range(half.p_range) {} >> RangeHalf(const RangeHalf<U> &half): p_range(half.p_range) {}
RangeHalf(const RangeHalf &half): p_range(half.p_range) {} RangeHalf(const RangeHalf &half): p_range(half.p_range) {}
RangeHalf(RangeHalf &&half): p_range(octa::move(half.p_range)) {} RangeHalf(RangeHalf &&half): p_range(move(half.p_range)) {}
RangeHalf &operator=(const RangeHalf &half) { RangeHalf &operator=(const RangeHalf &half) {
p_range = half.p_range; p_range = half.p_range;
@ -272,7 +272,7 @@ public:
} }
RangeHalf &operator=(RangeHalf &&half) { RangeHalf &operator=(RangeHalf &&half) {
p_range = octa::move(half.p_range); p_range = move(half.p_range);
return *this; return *this;
} }
@ -287,10 +287,10 @@ public:
} }
RangeDifference<T> add_n(RangeDifference<T> n) { RangeDifference<T> add_n(RangeDifference<T> n) {
return octa::detail::RangeAdd<RangeHalf<T>>::add_n(*this, n); return detail::RangeAdd<RangeHalf<T>>::add_n(*this, n);
} }
RangeDifference<T> sub_n(RangeDifference<T> n) { RangeDifference<T> sub_n(RangeDifference<T> n) {
return octa::detail::RangeAdd<RangeHalf<T>>::sub_n(*this, n); return detail::RangeAdd<RangeHalf<T>>::sub_n(*this, n);
} }
RangeReference<T> get() const { RangeReference<T> get() const {
@ -408,7 +408,7 @@ template<typename> struct ReverseRange;
template<typename> struct MoveRange; template<typename> struct MoveRange;
template<typename B, typename C, typename V, typename R = V &, template<typename B, typename C, typename V, typename R = V &,
typename S = octa::Size, typename D = octa::Ptrdiff typename S = Size, typename D = Ptrdiff
> struct InputRange { > struct InputRange {
using Category = C; using Category = C;
using Size = S; using Size = S;
@ -416,27 +416,27 @@ template<typename B, typename C, typename V, typename R = V &,
using Value = V; using Value = V;
using Reference = R; using Reference = R;
octa::detail::RangeIterator<B> begin() const { detail::RangeIterator<B> begin() const {
return octa::detail::RangeIterator<B>((const B &)*this); return detail::RangeIterator<B>((const B &)*this);
} }
octa::detail::RangeIterator<B> end() const { detail::RangeIterator<B> end() const {
return octa::detail::RangeIterator<B>(); return detail::RangeIterator<B>();
} }
Size pop_front_n(Size n) { Size pop_front_n(Size n) {
return octa::detail::pop_front_n<B>(*((B *)this), n); return detail::pop_front_n<B>(*((B *)this), n);
} }
Size pop_back_n(Size n) { Size pop_back_n(Size n) {
return octa::detail::pop_back_n<B>(*((B *)this), n); return detail::pop_back_n<B>(*((B *)this), n);
} }
Size push_front_n(Size n) { Size push_front_n(Size n) {
return octa::detail::push_front_n<B>(*((B *)this), n); return detail::push_front_n<B>(*((B *)this), n);
} }
Size push_back_n(Size n) { Size push_back_n(Size n) {
return octa::detail::push_back_n<B>(*((B *)this), n); return detail::push_back_n<B>(*((B *)this), n);
} }
B iter() const { B iter() const {
@ -463,8 +463,8 @@ template<typename B, typename C, typename V, typename R = V &,
} }
template<typename OR, template<typename OR,
typename = octa::EnableIf<octa::IsOutputRange<OR>::value typename = EnableIf<IsOutputRange<OR>::value>
>> Size copy(OR &&orange, Size n = -1) { > Size copy(OR &&orange, Size n = -1) {
B r(*((B *)this)); B r(*((B *)this));
Size on = n; Size on = n;
for (; n && !r.empty(); --n) { for (; n && !r.empty(); --n) {
@ -474,7 +474,7 @@ template<typename B, typename C, typename V, typename R = V &,
return (on - n); return (on - n);
} }
Size copy(octa::RemoveCv<Value> *p, Size n = -1) { Size copy(RemoveCv<Value> *p, Size n = -1) {
B r(*((B *)this)); B r(*((B *)this));
Size on = n; Size on = n;
for (; n && !r.empty(); --n) { for (; n && !r.empty(); --n) {
@ -501,7 +501,7 @@ auto citer(const T &r) -> decltype(r.iter()) {
} }
template<typename B, typename V, typename R = V &, template<typename B, typename V, typename R = V &,
typename S = octa::Size, typename D = octa::Ptrdiff typename S = Size, typename D = Ptrdiff
> struct OutputRange { > struct OutputRange {
using Category = OutputRangeTag; using Category = OutputRangeTag;
using Size = S; using Size = S;
@ -533,12 +533,12 @@ public:
HalfRange() = delete; HalfRange() = delete;
HalfRange(const HalfRange &range): p_beg(range.p_beg), HalfRange(const HalfRange &range): p_beg(range.p_beg),
p_end(range.p_end) {} p_end(range.p_end) {}
HalfRange(HalfRange &&range): p_beg(octa::move(range.p_beg)), HalfRange(HalfRange &&range): p_beg(move(range.p_beg)),
p_end(octa::move(range.p_end)) {} p_end(move(range.p_end)) {}
HalfRange(const T &beg, const T &end): p_beg(beg), HalfRange(const T &beg, const T &end): p_beg(beg),
p_end(end) {} p_end(end) {}
HalfRange(T &&beg, T &&end): p_beg(octa::move(beg)), HalfRange(T &&beg, T &&end): p_beg(move(beg)),
p_end(octa::move(end)) {} p_end(move(end)) {}
HalfRange &operator=(const HalfRange &range) { HalfRange &operator=(const HalfRange &range) {
p_beg = range.p_beg; p_beg = range.p_beg;
@ -547,8 +547,8 @@ public:
} }
HalfRange &operator=(HalfRange &&range) { HalfRange &operator=(HalfRange &&range) {
p_beg = octa::move(range.p_beg); p_beg = move(range.p_beg);
p_end = octa::move(range.p_end); p_end = move(range.p_end);
return *this; return *this;
} }
@ -601,7 +601,7 @@ public:
return p_beg.range().put(v); return p_beg.range().put(v);
} }
bool put(RangeValue<Rtype> &&v) { bool put(RangeValue<Rtype> &&v) {
return p_beg.range().put(octa::move(v)); return p_beg.range().put(move(v));
} }
}; };
@ -620,14 +620,14 @@ public:
ReverseRange() = delete; ReverseRange() = delete;
ReverseRange(const T &range): p_range(range) {} ReverseRange(const T &range): p_range(range) {}
ReverseRange(const ReverseRange &it): p_range(it.p_range) {} ReverseRange(const ReverseRange &it): p_range(it.p_range) {}
ReverseRange(ReverseRange &&it): p_range(octa::move(it.p_range)) {} ReverseRange(ReverseRange &&it): p_range(move(it.p_range)) {}
ReverseRange &operator=(const ReverseRange &v) { ReverseRange &operator=(const ReverseRange &v) {
p_range = v.p_range; p_range = v.p_range;
return *this; return *this;
} }
ReverseRange &operator=(ReverseRange &&v) { ReverseRange &operator=(ReverseRange &&v) {
p_range = octa::move(v.p_range); p_range = move(v.p_range);
return *this; return *this;
} }
ReverseRange &operator=(const T &v) { ReverseRange &operator=(const T &v) {
@ -635,7 +635,7 @@ public:
return *this; return *this;
} }
ReverseRange &operator=(T &&v) { ReverseRange &operator=(T &&v) {
p_range = octa::move(v); p_range = move(v);
return *this; return *this;
} }
@ -695,14 +695,14 @@ public:
MoveRange() = delete; MoveRange() = delete;
MoveRange(const T &range): p_range(range) {} MoveRange(const T &range): p_range(range) {}
MoveRange(const MoveRange &it): p_range(it.p_range) {} MoveRange(const MoveRange &it): p_range(it.p_range) {}
MoveRange(MoveRange &&it): p_range(octa::move(it.p_range)) {} MoveRange(MoveRange &&it): p_range(move(it.p_range)) {}
MoveRange &operator=(const MoveRange &v) { MoveRange &operator=(const MoveRange &v) {
p_range = v.p_range; p_range = v.p_range;
return *this; return *this;
} }
MoveRange &operator=(MoveRange &&v) { MoveRange &operator=(MoveRange &&v) {
p_range = octa::move(v.p_range); p_range = move(v.p_range);
return *this; return *this;
} }
MoveRange &operator=(const T &v) { MoveRange &operator=(const T &v) {
@ -710,7 +710,7 @@ public:
return *this; return *this;
} }
MoveRange &operator=(T &&v) { MoveRange &operator=(T &&v) {
p_range = octa::move(v); p_range = move(v);
return *this; return *this;
} }
@ -743,17 +743,17 @@ public:
Rsize push_front_n(Rsize n) { return p_range.push_front_n(n); } Rsize push_front_n(Rsize n) { return p_range.push_front_n(n); }
Rsize push_back_n(Rsize n) { return p_range.push_back_n(n); } Rsize push_back_n(Rsize n) { return p_range.push_back_n(n); }
Rref front() const { return octa::move(p_range.front()); } Rref front() const { return move(p_range.front()); }
Rref back() const { return octa::move(p_range.back()); } Rref back() const { return move(p_range.back()); }
Rref operator[](Rsize i) const { return octa::move(p_range[i]); } Rref operator[](Rsize i) const { return move(p_range[i]); }
MoveRange<T> slice(Rsize start, Rsize end) const { MoveRange<T> slice(Rsize start, Rsize end) const {
return MoveRange<T>(p_range.slice(start, end)); return MoveRange<T>(p_range.slice(start, end));
} }
bool put(const Rval &v) { return p_range.put(v); } bool put(const Rval &v) { return p_range.put(v); }
bool put(Rval &&v) { return p_range.put(octa::move(v)); } bool put(Rval &&v) { return p_range.put(move(v)); }
}; };
template<typename T> template<typename T>
@ -792,10 +792,10 @@ template<typename T>
struct PointerRange: InputRange<PointerRange<T>, FiniteRandomAccessRangeTag, T> { struct PointerRange: InputRange<PointerRange<T>, FiniteRandomAccessRangeTag, T> {
PointerRange() = delete; PointerRange() = delete;
PointerRange(T *beg, T *end): p_beg(beg), p_end(end) {} PointerRange(T *beg, T *end): p_beg(beg), p_end(end) {}
PointerRange(T *beg, octa::Size n): p_beg(beg), p_end(beg + n) {} PointerRange(T *beg, Size n): p_beg(beg), p_end(beg + n) {}
template<typename U, typename = octa::EnableIf< template<typename U, typename = EnableIf<
octa::IsConvertible<U *, T *>::value IsConvertible<U *, T *>::value
>> PointerRange(const PointerRange<U> &v): >> PointerRange(const PointerRange<U> &v):
p_beg(&v[0]), p_end(&v[v.size()]) {} p_beg(&v[0]), p_end(&v[v.size()]) {}
@ -817,8 +817,8 @@ struct PointerRange: InputRange<PointerRange<T>, FiniteRandomAccessRangeTag, T>
--p_beg; return true; --p_beg; return true;
} }
octa::Size pop_front_n(octa::Size n) { Size pop_front_n(Size n) {
octa::Size olen = p_end - p_beg; Size olen = p_end - p_beg;
p_beg += n; p_beg += n;
if (p_beg > p_end) { if (p_beg > p_end) {
p_beg = p_end; p_beg = p_end;
@ -827,7 +827,7 @@ struct PointerRange: InputRange<PointerRange<T>, FiniteRandomAccessRangeTag, T>
return n; return n;
} }
octa::Size push_front_n(octa::Size n) { Size push_front_n(Size n) {
p_beg -= n; return true; p_beg -= n; return true;
} }
@ -837,7 +837,7 @@ struct PointerRange: InputRange<PointerRange<T>, FiniteRandomAccessRangeTag, T>
return p_beg == range.p_beg; return p_beg == range.p_beg;
} }
octa::Ptrdiff distance_front(const PointerRange &range) const { Ptrdiff distance_front(const PointerRange &range) const {
return range.p_beg - p_beg; return range.p_beg - p_beg;
} }
@ -851,8 +851,8 @@ struct PointerRange: InputRange<PointerRange<T>, FiniteRandomAccessRangeTag, T>
++p_end; return true; ++p_end; return true;
} }
octa::Size pop_back_n(octa::Size n) { Size pop_back_n(Size n) {
octa::Size olen = p_end - p_beg; Size olen = p_end - p_beg;
p_end -= n; p_end -= n;
if (p_end < p_beg) { if (p_end < p_beg) {
p_end = p_beg; p_end = p_beg;
@ -861,7 +861,7 @@ struct PointerRange: InputRange<PointerRange<T>, FiniteRandomAccessRangeTag, T>
return n; return n;
} }
octa::Size push_back_n(octa::Size n) { Size push_back_n(Size n) {
p_end += n; return true; p_end += n; return true;
} }
@ -871,18 +871,18 @@ struct PointerRange: InputRange<PointerRange<T>, FiniteRandomAccessRangeTag, T>
return p_end == range.p_end; return p_end == range.p_end;
} }
octa::Ptrdiff distance_back(const PointerRange &range) const { Ptrdiff distance_back(const PointerRange &range) const {
return range.p_end - p_end; return range.p_end - p_end;
} }
/* satisfy FiniteRandomAccessRange */ /* satisfy FiniteRandomAccessRange */
octa::Size size() const { return p_end - p_beg; } Size size() const { return p_end - p_beg; }
PointerRange slice(octa::Size start, octa::Size end) const { PointerRange slice(Size start, Size end) const {
return PointerRange(p_beg + start, p_beg + end); return PointerRange(p_beg + start, p_beg + end);
} }
T &operator[](octa::Size i) const { return p_beg[i]; } T &operator[](Size i) const { return p_beg[i]; }
/* satisfy OutputRange */ /* satisfy OutputRange */
bool put(const T &v) { bool put(const T &v) {
@ -892,33 +892,33 @@ struct PointerRange: InputRange<PointerRange<T>, FiniteRandomAccessRangeTag, T>
} }
bool put(T &&v) { bool put(T &&v) {
if (empty()) return false; if (empty()) return false;
*(p_beg++) = octa::move(v); *(p_beg++) = move(v);
return true; return true;
} }
octa::Size put_n(const T *p, octa::Size n) { Size put_n(const T *p, Size n) {
octa::Size ret = size(); Size ret = size();
if (n < ret) ret = n; if (n < ret) ret = n;
if (octa::IsPod<T>()) { if (IsPod<T>()) {
memcpy(p_beg, p, ret * sizeof(T)); memcpy(p_beg, p, ret * sizeof(T));
p_beg += ret; p_beg += ret;
return ret; return ret;
} }
for (octa::Size i = ret; i; --i) for (Size i = ret; i; --i)
*p_beg++ = *p++; *p_beg++ = *p++;
return ret; return ret;
} }
template<typename R, template<typename R,
typename = octa::EnableIf<octa::IsOutputRange<R>::value typename = EnableIf<IsOutputRange<R>::value
>> octa::Size copy(R &&orange, octa::Size n = -1) { >> Size copy(R &&orange, Size n = -1) {
octa::Size c = size(); Size c = size();
if (n < c) c = n; if (n < c) c = n;
return orange.put_n(p_beg, c); return orange.put_n(p_beg, c);
} }
octa::Size copy(octa::RemoveCv<T> *p, octa::Size n = -1) { Size copy(RemoveCv<T> *p, Size n = -1) {
octa::Size c = size(); Size c = size();
if (n < c) c = n; if (n < c) c = n;
return copy(PointerRange(p, c), c); return copy(PointerRange(p, c), c);
} }
@ -927,12 +927,12 @@ private:
T *p_beg, *p_end; T *p_beg, *p_end;
}; };
template<typename T, octa::Size N> template<typename T, Size N>
PointerRange<T> iter(T (&array)[N]) { PointerRange<T> iter(T (&array)[N]) {
return PointerRange<T>(array, N); return PointerRange<T>(array, N);
} }
template<typename T, octa::Size N> template<typename T, Size N>
PointerRange<const T> iter(const T (&array)[N]) { PointerRange<const T> iter(const T (&array)[N]) {
return PointerRange<const T>(array, N); return PointerRange<const T>(array, N);
} }
@ -965,7 +965,7 @@ public:
p_range(it.p_range), p_index(it.p_index) {} p_range(it.p_range), p_index(it.p_index) {}
EnumeratedRange(EnumeratedRange &&it): EnumeratedRange(EnumeratedRange &&it):
p_range(octa::move(it.p_range)), p_index(it.p_index) {} p_range(move(it.p_range)), p_index(it.p_index) {}
EnumeratedRange &operator=(const EnumeratedRange &v) { EnumeratedRange &operator=(const EnumeratedRange &v) {
p_range = v.p_range; p_range = v.p_range;
@ -973,7 +973,7 @@ public:
return *this; return *this;
} }
EnumeratedRange &operator=(EnumeratedRange &&v) { EnumeratedRange &operator=(EnumeratedRange &&v) {
p_range = octa::move(v.p_range); p_range = move(v.p_range);
p_index = v.p_index; p_index = v.p_index;
return *this; return *this;
} }
@ -983,7 +983,7 @@ public:
return *this; return *this;
} }
EnumeratedRange &operator=(T &&v) { EnumeratedRange &operator=(T &&v) {
p_range = octa::move(v); p_range = move(v);
p_index = 0; p_index = 0;
return *this; return *this;
} }
@ -1032,14 +1032,14 @@ public:
p_remaining(rem) {} p_remaining(rem) {}
TakeRange(const TakeRange &it): p_range(it.p_range), TakeRange(const TakeRange &it): p_range(it.p_range),
p_remaining(it.p_remaining) {} p_remaining(it.p_remaining) {}
TakeRange(TakeRange &&it): p_range(octa::move(it.p_range)), TakeRange(TakeRange &&it): p_range(move(it.p_range)),
p_remaining(it.p_remaining) {} p_remaining(it.p_remaining) {}
TakeRange &operator=(const TakeRange &v) { TakeRange &operator=(const TakeRange &v) {
p_range = v.p_range; p_remaining = v.p_remaining; return *this; p_range = v.p_range; p_remaining = v.p_remaining; return *this;
} }
TakeRange &operator=(TakeRange &&v) { TakeRange &operator=(TakeRange &&v) {
p_range = octa::move(v.p_range); p_range = move(v.p_range);
p_remaining = v.p_remaining; p_remaining = v.p_remaining;
return *this; return *this;
} }
@ -1086,14 +1086,14 @@ public:
p_chunksize(chs) {} p_chunksize(chs) {}
ChunksRange(const ChunksRange &it): p_range(it.p_range), ChunksRange(const ChunksRange &it): p_range(it.p_range),
p_chunksize(it.p_chunksize) {} p_chunksize(it.p_chunksize) {}
ChunksRange(ChunksRange &&it): p_range(octa::move(it.p_range)), ChunksRange(ChunksRange &&it): p_range(move(it.p_range)),
p_chunksize(it.p_chunksize) {} p_chunksize(it.p_chunksize) {}
ChunksRange &operator=(const ChunksRange &v) { ChunksRange &operator=(const ChunksRange &v) {
p_range = v.p_range; p_chunksize = v.p_chunksize; return *this; p_range = v.p_range; p_chunksize = v.p_chunksize; return *this;
} }
ChunksRange &operator=(ChunksRange &&v) { ChunksRange &operator=(ChunksRange &&v) {
p_range = octa::move(v.p_range); p_range = move(v.p_range);
p_chunksize = v.p_chunksize; p_chunksize = v.p_chunksize;
return *this; return *this;
} }
@ -1122,9 +1122,9 @@ struct AppenderRange: OutputRange<AppenderRange<T>, typename T::Value,
typename T::Reference, typename T::Size, typename T::Difference> { typename T::Reference, typename T::Size, typename T::Difference> {
AppenderRange(): p_data() {} AppenderRange(): p_data() {}
AppenderRange(const T &v): p_data(v) {} AppenderRange(const T &v): p_data(v) {}
AppenderRange(T &&v): p_data(octa::move(v)) {} AppenderRange(T &&v): p_data(move(v)) {}
AppenderRange(const AppenderRange &v): p_data(v.p_data) {} AppenderRange(const AppenderRange &v): p_data(v.p_data) {}
AppenderRange(AppenderRange &&v): p_data(octa::move(v.p_data)) {} AppenderRange(AppenderRange &&v): p_data(move(v.p_data)) {}
AppenderRange &operator=(const AppenderRange &v) { AppenderRange &operator=(const AppenderRange &v) {
p_data = v.p_data; p_data = v.p_data;
@ -1132,7 +1132,7 @@ struct AppenderRange: OutputRange<AppenderRange<T>, typename T::Value,
} }
AppenderRange &operator=(AppenderRange &&v) { AppenderRange &operator=(AppenderRange &&v) {
p_data = octa::move(v.p_data); p_data = move(v.p_data);
return *this; return *this;
} }
@ -1142,7 +1142,7 @@ struct AppenderRange: OutputRange<AppenderRange<T>, typename T::Value,
} }
AppenderRange &operator=(T &&v) { AppenderRange &operator=(T &&v) {
p_data = octa::move(v); p_data = move(v);
return *this; return *this;
} }
@ -1160,7 +1160,7 @@ struct AppenderRange: OutputRange<AppenderRange<T>, typename T::Value,
} }
bool put(typename T::Value &&v) { bool put(typename T::Value &&v) {
p_data.push(octa::move(v)); p_data.push(move(v));
return true; return true;
} }
@ -1176,11 +1176,11 @@ AppenderRange<T> appender() {
template<typename T> template<typename T>
AppenderRange<T> appender(T &&v) { AppenderRange<T> appender(T &&v) {
return AppenderRange<T>(octa::forward<T>(v)); return AppenderRange<T>(forward<T>(v));
} }
// range of // range of
template<typename T> using RangeOf = decltype(octa::iter(octa::declval<T>())); template<typename T> using RangeOf = decltype(iter(declval<T>()));
} /* namespace octa */ } /* namespace octa */

View File

@ -30,56 +30,56 @@ namespace detail {
}; };
template<typename T, typename H, typename C, typename A, bool IsMultihash> template<typename T, typename H, typename C, typename A, bool IsMultihash>
struct SetImpl: octa::detail::Hashtable< struct SetImpl: detail::Hashtable<
octa::detail::SetBase<T, A>, T, T, T, H, C, A, IsMultihash detail::SetBase<T, A>, T, T, T, H, C, A, IsMultihash
> { > {
private: private:
using Base = octa::detail::Hashtable< using Base = detail::Hashtable<
octa::detail::SetBase<T, A>, T, T, T, H, C, A, IsMultihash detail::SetBase<T, A>, T, T, T, H, C, A, IsMultihash
>; >;
public: public:
using Key = T; using Key = T;
using Size = octa::Size; using Size = Size;
using Difference = octa::Ptrdiff; using Difference = Ptrdiff;
using Hasher = H; using Hasher = H;
using KeyEqual = C; using KeyEqual = C;
using Value = T; using Value = T;
using Reference = Value &; using Reference = Value &;
using Pointer = octa::AllocatorPointer<A>; using Pointer = AllocatorPointer<A>;
using ConstPointer = octa::AllocatorConstPointer<A>; using ConstPointer = AllocatorConstPointer<A>;
using Range = octa::HashRange<T>; using Range = HashRange<T>;
using ConstRange = octa::HashRange<const T>; using ConstRange = HashRange<const T>;
using LocalRange = octa::BucketRange<T>; using LocalRange = BucketRange<T>;
using ConstLocalRange = octa::BucketRange<const T>; using ConstLocalRange = BucketRange<const T>;
using Allocator = A; using Allocator = A;
explicit SetImpl(octa::Size size, const H &hf = H(), explicit SetImpl(Size size, const H &hf = H(),
const C &eqf = C(), const A &alloc = A() const C &eqf = C(), const A &alloc = A()
): Base(size, hf, eqf, alloc) {} ): Base(size, hf, eqf, alloc) {}
SetImpl(): SetImpl(0) {} SetImpl(): SetImpl(0) {}
explicit SetImpl(const A &alloc): SetImpl(0, H(), C(), alloc) {} explicit SetImpl(const A &alloc): SetImpl(0, H(), C(), alloc) {}
SetImpl(octa::Size size, const A &alloc): SetImpl(Size size, const A &alloc):
SetImpl(size, H(), C(), alloc) {} SetImpl(size, H(), C(), alloc) {}
SetImpl(octa::Size size, const H &hf, const A &alloc): SetImpl(Size size, const H &hf, const A &alloc):
SetImpl(size, hf, C(), alloc) {} SetImpl(size, hf, C(), alloc) {}
SetImpl(const SetImpl &m): Base(m, SetImpl(const SetImpl &m): Base(m,
octa::allocator_container_copy(m.get_alloc())) {} allocator_container_copy(m.get_alloc())) {}
SetImpl(const SetImpl &m, const A &alloc): Base(m, alloc) {} SetImpl(const SetImpl &m, const A &alloc): Base(m, alloc) {}
SetImpl(SetImpl &&m): Base(octa::move(m)) {} SetImpl(SetImpl &&m): Base(move(m)) {}
SetImpl(SetImpl &&m, const A &alloc): Base(octa::move(m), alloc) {} SetImpl(SetImpl &&m, const A &alloc): Base(move(m), alloc) {}
template<typename R, typename = octa::EnableIf< template<typename R, typename = EnableIf<
octa::IsInputRange<R>::value && IsInputRange<R>::value &&
octa::IsConvertible<RangeReference<R>, Value>::value IsConvertible<RangeReference<R>, Value>::value
>> SetImpl(R range, octa::Size size = 0, const H &hf = H(), >> SetImpl(R range, Size size = 0, const H &hf = H(),
const C &eqf = C(), const A &alloc = A() const C &eqf = C(), const A &alloc = A()
): Base(size ? size : octa::detail::estimate_hrsize(range), ): Base(size ? size : detail::estimate_hrsize(range),
hf, eqf, alloc) { hf, eqf, alloc) {
for (; !range.empty(); range.pop_front()) for (; !range.empty(); range.pop_front())
Base::emplace(range.front()); Base::emplace(range.front());
@ -87,23 +87,23 @@ namespace detail {
} }
template<typename R> template<typename R>
SetImpl(R range, octa::Size size, const A &alloc) SetImpl(R range, Size size, const A &alloc)
: SetImpl(range, size, H(), C(), alloc) {} : SetImpl(range, size, H(), C(), alloc) {}
template<typename R> template<typename R>
SetImpl(R range, octa::Size size, const H &hf, const A &alloc) SetImpl(R range, Size size, const H &hf, const A &alloc)
: SetImpl(range, size, hf, C(), alloc) {} : SetImpl(range, size, hf, C(), alloc) {}
SetImpl(octa::InitializerList<Value> init, octa::Size size = 0, SetImpl(InitializerList<Value> init, Size size = 0,
const H &hf = H(), const C &eqf = C(), const A &alloc = A() const H &hf = H(), const C &eqf = C(), const A &alloc = A()
): SetImpl(octa::iter(init), size, hf, eqf, alloc) {} ): SetImpl(iter(init), size, hf, eqf, alloc) {}
SetImpl(octa::InitializerList<Value> init, octa::Size size, const A &alloc) SetImpl(InitializerList<Value> init, Size size, const A &alloc)
: SetImpl(octa::iter(init), size, H(), C(), alloc) {} : SetImpl(iter(init), size, H(), C(), alloc) {}
SetImpl(octa::InitializerList<Value> init, octa::Size size, const H &hf, SetImpl(InitializerList<Value> init, Size size, const H &hf,
const A &alloc const A &alloc
): SetImpl(octa::iter(init), size, hf, C(), alloc) {} ): SetImpl(iter(init), size, hf, C(), alloc) {}
SetImpl &operator=(const SetImpl &m) { SetImpl &operator=(const SetImpl &m) {
Base::operator=(m); Base::operator=(m);
@ -111,13 +111,13 @@ namespace detail {
} }
SetImpl &operator=(SetImpl &&m) { SetImpl &operator=(SetImpl &&m) {
Base::operator=(octa::move(m)); Base::operator=(move(m));
return *this; return *this;
} }
template<typename R, typename = octa::EnableIf< template<typename R, typename = EnableIf<
octa::IsInputRange<R>::value && IsInputRange<R>::value &&
octa::IsConvertible<RangeReference<R>, Value>::value IsConvertible<RangeReference<R>, Value>::value
>> SetImpl &operator=(R range) { >> SetImpl &operator=(R range) {
Base::assign_range(range); Base::assign_range(range);
return *this; return *this;
@ -136,17 +136,17 @@ namespace detail {
template< template<
typename T, typename T,
typename H = octa::ToHash<T>, typename H = ToHash<T>,
typename C = octa::Equal<T>, typename C = Equal<T>,
typename A = octa::Allocator<T> typename A = Allocator<T>
> using Set = octa::detail::SetImpl<T, H, C, A, false>; > using Set = detail::SetImpl<T, H, C, A, false>;
template< template<
typename T, typename T,
typename H = octa::ToHash<T>, typename H = ToHash<T>,
typename C = octa::Equal<T>, typename C = Equal<T>,
typename A = octa::Allocator<T> typename A = Allocator<T>
> using Multiset = octa::detail::SetImpl<T, H, C, A, true>; > using Multiset = detail::SetImpl<T, H, C, A, true>;
} /* namespace octa */ } /* namespace octa */

View File

@ -30,16 +30,16 @@ enum class StreamSeek {
set = SEEK_SET set = SEEK_SET
}; };
template<typename T = char, bool = octa::IsPod<T>::value> template<typename T = char, bool = IsPod<T>::value>
struct StreamRange; struct StreamRange;
namespace detail { namespace detail {
template<octa::Size N> template<Size N>
struct FormatOutRange: octa::OutputRange<FormatOutRange<N>, char> { struct FormatOutRange: OutputRange<FormatOutRange<N>, char> {
FormatOutRange(char *buf): buf(buf), idx(0) {} FormatOutRange(char *buf): buf(buf), idx(0) {}
FormatOutRange(const FormatOutRange &r): buf(r.buf), idx(r.idx) {} FormatOutRange(const FormatOutRange &r): buf(r.buf), idx(r.idx) {}
char *buf; char *buf;
octa::Size idx; Size idx;
bool put(char v) { bool put(char v) {
if (idx < N) { if (idx < N) {
buf[idx++] = v; buf[idx++] = v;
@ -74,30 +74,30 @@ struct Stream {
virtual bool flush() { return true; } virtual bool flush() { return true; }
virtual octa::Size read_bytes(void *, octa::Size) { return 0; } virtual Size read_bytes(void *, Size) { return 0; }
virtual octa::Size write_bytes(const void *, octa::Size) { return 0; } virtual Size write_bytes(const void *, Size) { return 0; }
virtual int getchar() { virtual int getchar() {
octa::byte c; byte c;
return (read_bytes(&c, 1) == 1) ? c : -1; return (read_bytes(&c, 1) == 1) ? c : -1;
} }
virtual bool putchar(int c) { virtual bool putchar(int c) {
octa::byte wc = octa::byte(c); byte wc = byte(c);
return write_bytes(&wc, 1) == 1; return write_bytes(&wc, 1) == 1;
} }
virtual bool write(const char *s) { virtual bool write(const char *s) {
octa::Size len = strlen(s); Size len = strlen(s);
return write_bytes(s, len) == len; return write_bytes(s, len) == len;
} }
virtual bool write(const octa::String &s) { virtual bool write(const String &s) {
return write_bytes(s.data(), s.size()) == s.size(); return write_bytes(s.data(), s.size()) == s.size();
} }
template<typename T> bool write(const T &v) { template<typename T> bool write(const T &v) {
return write(octa::to_string(v)); return write(to_string(v));
} }
template<typename T, typename ...A> template<typename T, typename ...A>
@ -105,7 +105,7 @@ struct Stream {
return write(v) && write(args...); return write(v) && write(args...);
} }
virtual bool writeln(const octa::String &s) { virtual bool writeln(const String &s) {
return write(s) && putchar('\n'); return write(s) && putchar('\n');
} }
@ -125,19 +125,19 @@ struct Stream {
template<typename ...A> template<typename ...A>
bool writef(const char *fmt, const A &...args) { bool writef(const char *fmt, const A &...args) {
char buf[512]; char buf[512];
octa::Size need = octa::format(octa::detail::FormatOutRange< Size need = format(detail::FormatOutRange<sizeof(buf)>(buf),
sizeof(buf)>(buf), fmt, args...); fmt, args...);
if (need < sizeof(buf)) if (need < sizeof(buf))
return write_bytes(buf, need) == need; return write_bytes(buf, need) == need;
octa::String s; String s;
s.reserve(need); s.reserve(need);
s[need] = '\0'; s[need] = '\0';
octa::format(s.iter(), fmt, args...); format(s.iter(), fmt, args...);
return write_bytes(s.data(), need) == need; return write_bytes(s.data(), need) == need;
} }
template<typename ...A> template<typename ...A>
bool writef(const octa::String &fmt, const A &...args) { bool writef(const String &fmt, const A &...args) {
return writef(fmt.data(), args...); return writef(fmt.data(), args...);
} }
@ -147,14 +147,14 @@ struct Stream {
} }
template<typename ...A> template<typename ...A>
bool writefln(const octa::String &fmt, const A &...args) { bool writefln(const String &fmt, const A &...args) {
return writefln(fmt.data(), args...); return writefln(fmt.data(), args...);
} }
template<typename T = char> template<typename T = char>
StreamRange<T> iter(); StreamRange<T> iter();
template<typename T> octa::Size put(const T *v, octa::Size count) { template<typename T> Size put(const T *v, Size count) {
return write_bytes(v, count * sizeof(T)) / sizeof(T); return write_bytes(v, count * sizeof(T)) / sizeof(T);
} }
@ -162,7 +162,7 @@ struct Stream {
return write_bytes(&v, sizeof(T)) == sizeof(T); return write_bytes(&v, sizeof(T)) == sizeof(T);
} }
template<typename T> octa::Size get(T *v, octa::Size count) { template<typename T> Size get(T *v, Size count) {
return read_bytes(v, count * sizeof(T)) / sizeof(T); return read_bytes(v, count * sizeof(T)) / sizeof(T);
} }
@ -178,7 +178,7 @@ struct Stream {
template<typename T> template<typename T>
struct StreamRange<T, true>: InputRange< struct StreamRange<T, true>: InputRange<
StreamRange<T>, octa::InputRangeTag, T, T, octa::Size, StreamOffset StreamRange<T>, InputRangeTag, T, T, Size, StreamOffset
> { > {
StreamRange() = delete; StreamRange() = delete;
StreamRange(Stream &s): p_stream(&s), p_size(s.size()) {} StreamRange(Stream &s): p_stream(&s), p_size(s.size()) {}
@ -205,17 +205,17 @@ struct StreamRange<T, true>: InputRange<
} }
bool put(T val) { bool put(T val) {
octa::Size v = p_stream->write_bytes(&val, sizeof(T)); Size v = p_stream->write_bytes(&val, sizeof(T));
p_size += v; p_size += v;
return (v == sizeof(T)); return (v == sizeof(T));
} }
octa::Size put_n(const T *p, octa::Size n) { Size put_n(const T *p, Size n) {
return p_stream->put(p, n); return p_stream->put(p, n);
} }
octa::Size copy(octa::RemoveCv<T> *p, octa::Size n = -1) { Size copy(RemoveCv<T> *p, Size n = -1) {
if (n == octa::Size(-1)) { if (n == Size(-1)) {
n = p_stream->size() / sizeof(T); n = p_stream->size() / sizeof(T);
} }
return p_stream->get(p, n); return p_stream->get(p, n);

View File

@ -14,9 +14,9 @@
#include "octa/vector.hh" #include "octa/vector.hh"
namespace octa { namespace octa {
static constexpr octa::Size npos = -1; static constexpr Size npos = -1;
template<typename T, typename A = octa::Allocator<T>> class StringBase; template<typename T, typename A = Allocator<T>> class StringBase;
template<typename T> template<typename T>
struct StringRangeBase: InputRange< struct StringRangeBase: InputRange<
@ -24,7 +24,7 @@ struct StringRangeBase: InputRange<
> { > {
StringRangeBase() = delete; StringRangeBase() = delete;
StringRangeBase(T *beg, T *end): p_beg(beg), p_end(end) {} StringRangeBase(T *beg, T *end): p_beg(beg), p_end(end) {}
StringRangeBase(T *beg, octa::Size n): p_beg(beg), p_end(beg + n) {} StringRangeBase(T *beg, Size n): p_beg(beg), p_end(beg + n) {}
/* TODO: traits for utf-16/utf-32 string lengths, for now assume char */ /* TODO: traits for utf-16/utf-32 string lengths, for now assume char */
StringRangeBase(T *beg): p_beg(beg), p_end(beg + strlen(beg)) {} StringRangeBase(T *beg): p_beg(beg), p_end(beg + strlen(beg)) {}
@ -32,8 +32,8 @@ struct StringRangeBase: InputRange<
StringRangeBase(const StringBase<T, A> &s): p_beg(s.data()), StringRangeBase(const StringBase<T, A> &s): p_beg(s.data()),
p_end(s.data() + s.size()) {} p_end(s.data() + s.size()) {}
template<typename U, typename = octa::EnableIf< template<typename U, typename = EnableIf<
octa::IsConvertible<U *, T *>::value IsConvertible<U *, T *>::value
>> StringRangeBase(const StringRangeBase<U> &v): >> StringRangeBase(const StringRangeBase<U> &v):
p_beg(&v[0]), p_end(&v[v.size()]) {} p_beg(&v[0]), p_end(&v[v.size()]) {}
@ -59,8 +59,8 @@ struct StringRangeBase: InputRange<
} }
bool push_front() { --p_beg; return true; } bool push_front() { --p_beg; return true; }
octa::Size pop_front_n(octa::Size n) { Size pop_front_n(Size n) {
octa::Size olen = p_end - p_beg; Size olen = p_end - p_beg;
p_beg += n; p_beg += n;
if (p_beg > p_end) { if (p_beg > p_end) {
p_beg = p_end; p_beg = p_end;
@ -69,7 +69,7 @@ struct StringRangeBase: InputRange<
return n; return n;
} }
octa::Size push_front_n(octa::Size n) { p_beg -= n; return true; } Size push_front_n(Size n) { p_beg -= n; return true; }
T &front() const { return *p_beg; } T &front() const { return *p_beg; }
@ -77,7 +77,7 @@ struct StringRangeBase: InputRange<
return p_beg == range.p_beg; return p_beg == range.p_beg;
} }
octa::Ptrdiff distance_front(const StringRangeBase &range) const { Ptrdiff distance_front(const StringRangeBase &range) const {
return range.p_beg - p_beg; return range.p_beg - p_beg;
} }
@ -88,8 +88,8 @@ struct StringRangeBase: InputRange<
} }
bool push_back() { ++p_end; return true; } bool push_back() { ++p_end; return true; }
octa::Size pop_back_n(octa::Size n) { Size pop_back_n(Size n) {
octa::Size olen = p_end - p_beg; Size olen = p_end - p_beg;
p_end -= n; p_end -= n;
if (p_end < p_beg) { if (p_end < p_beg) {
p_end = p_beg; p_end = p_beg;
@ -98,7 +98,7 @@ struct StringRangeBase: InputRange<
return n; return n;
} }
octa::Size push_back_n(octa::Size n) { p_end += n; return true; } Size push_back_n(Size n) { p_end += n; return true; }
T &back() const { return *(p_end - 1); } T &back() const { return *(p_end - 1); }
@ -106,17 +106,17 @@ struct StringRangeBase: InputRange<
return p_end == range.p_end; return p_end == range.p_end;
} }
octa::Ptrdiff distance_back(const StringRangeBase &range) const { Ptrdiff distance_back(const StringRangeBase &range) const {
return range.p_end - p_end; return range.p_end - p_end;
} }
octa::Size size() const { return p_end - p_beg; } Size size() const { return p_end - p_beg; }
StringRangeBase slice(octa::Size start, octa::Size end) const { StringRangeBase slice(Size start, Size end) const {
return StringRangeBase(p_beg + start, p_beg + end); return StringRangeBase(p_beg + start, p_beg + end);
} }
T &operator[](octa::Size i) const { return p_beg[i]; } T &operator[](Size i) const { return p_beg[i]; }
bool put(T v) { bool put(T v) {
if (empty()) return false; if (empty()) return false;
@ -128,7 +128,7 @@ struct StringRangeBase: InputRange<
T *data() { return p_beg; } T *data() { return p_beg; }
const T *data() const { return p_beg; } const T *data() const { return p_beg; }
octa::Size to_hash() const { Size to_hash() const {
const T *d = data(); const T *d = data();
Size h = 5381, len = size(); Size h = 5381, len = size();
for (Size i = 0; i < len; ++i) for (Size i = 0; i < len; ++i)
@ -142,22 +142,22 @@ private:
template<typename T, typename A> template<typename T, typename A>
class StringBase { class StringBase {
octa::Vector<T, A> p_buf; Vector<T, A> p_buf;
void terminate() { void terminate() {
if (p_buf.empty() || (p_buf.back() != '\0')) p_buf.push('\0'); if (p_buf.empty() || (p_buf.back() != '\0')) p_buf.push('\0');
} }
public: public:
using Size = octa::Size; using Size = Size;
using Difference = octa::Ptrdiff; using Difference = Ptrdiff;
using Value = T; using Value = T;
using Reference = T &; using Reference = T &;
using ConstReference = const T &; using ConstReference = const T &;
using Pointer = octa::AllocatorPointer<A>; using Pointer = AllocatorPointer<A>;
using ConstPointer = octa::AllocatorConstPointer<A>; using ConstPointer = AllocatorConstPointer<A>;
using Range = octa::StringRangeBase<T>; using Range = StringRangeBase<T>;
using ConstRange = octa::StringRangeBase<const T>; using ConstRange = StringRangeBase<const T>;
using Allocator = A; using Allocator = A;
StringBase(const A &a = A()): p_buf(1, '\0', a) {} StringBase(const A &a = A()): p_buf(1, '\0', a) {}
@ -168,11 +168,11 @@ public:
StringBase(const StringBase &s): p_buf(s.p_buf) {} StringBase(const StringBase &s): p_buf(s.p_buf) {}
StringBase(const StringBase &s, const A &a): StringBase(const StringBase &s, const A &a):
p_buf(s.p_buf, a) {} p_buf(s.p_buf, a) {}
StringBase(StringBase &&s): p_buf(octa::move(s.p_buf)) {} StringBase(StringBase &&s): p_buf(move(s.p_buf)) {}
StringBase(StringBase &&s, const A &a): StringBase(StringBase &&s, const A &a):
p_buf(octa::move(s.p_buf), a) {} p_buf(move(s.p_buf), a) {}
StringBase(const StringBase &s, octa::Size pos, octa::Size len = npos, StringBase(const StringBase &s, Size pos, Size len = npos,
const A &a = A()): const A &a = A()):
p_buf(s.p_buf.iter().slice(pos, p_buf(s.p_buf.iter().slice(pos,
(len == npos) ? s.p_buf.size() : (pos + len)), a) { (len == npos) ? s.p_buf.size() : (pos + len)), a) {
@ -186,9 +186,9 @@ public:
StringBase(const Value *v, Size n, const A &a = A()): StringBase(const Value *v, Size n, const A &a = A()):
p_buf(ConstRange(v, n), a) {} p_buf(ConstRange(v, n), a) {}
template<typename R, typename = octa::EnableIf< template<typename R, typename = EnableIf<
octa::IsInputRange<R>::value && IsInputRange<R>::value &&
octa::IsConvertible<RangeReference<R>, Value>::value IsConvertible<RangeReference<R>, Value>::value
>> StringBase(R range, const A &a = A()): p_buf(range, a) { >> StringBase(R range, const A &a = A()): p_buf(range, a) {
terminate(); terminate();
} }
@ -200,37 +200,37 @@ public:
return *this; return *this;
} }
StringBase &operator=(StringBase &&v) { StringBase &operator=(StringBase &&v) {
p_buf.operator=(octa::move(v)); p_buf.operator=(move(v));
return *this; return *this;
} }
StringBase &operator=(const Value *v) { StringBase &operator=(const Value *v) {
p_buf = ConstRange(v, strlen(v) + 1); p_buf = ConstRange(v, strlen(v) + 1);
return *this; return *this;
} }
template<typename R, typename = octa::EnableIf< template<typename R, typename = EnableIf<
octa::IsInputRange<R>::value && IsInputRange<R>::value &&
octa::IsConvertible<RangeReference<R>, Value>::value IsConvertible<RangeReference<R>, Value>::value
>> StringBase &operator=(const R &r) { >> StringBase &operator=(const R &r) {
p_buf = r; p_buf = r;
terminate(); terminate();
return *this; return *this;
} }
void resize(octa::Size n, T v = T()) { void resize(Size n, T v = T()) {
p_buf.pop(); p_buf.pop();
p_buf.resize(n, v); p_buf.resize(n, v);
terminate(); terminate();
} }
void reserve(octa::Size n) { void reserve(Size n) {
p_buf.reserve(n + 1); p_buf.reserve(n + 1);
} }
T &operator[](octa::Size i) { return p_buf[i]; } T &operator[](Size i) { return p_buf[i]; }
const T &operator[](octa::Size i) const { return p_buf[i]; } const T &operator[](Size i) const { return p_buf[i]; }
T &at(octa::Size i) { return p_buf[i]; } T &at(Size i) { return p_buf[i]; }
const T &at(octa::Size i) const { return p_buf[i]; } const T &at(Size i) const { return p_buf[i]; }
T &front() { return p_buf[0]; } T &front() { return p_buf[0]; }
const T &front() const { return p_buf[0]; }; const T &front() const { return p_buf[0]; };
@ -241,15 +241,15 @@ public:
Value *data() { return p_buf.data(); } Value *data() { return p_buf.data(); }
const Value *data() const { return p_buf.data(); } const Value *data() const { return p_buf.data(); }
octa::Size size() const { Size size() const {
return p_buf.size() - 1; return p_buf.size() - 1;
} }
octa::Size capacity() const { Size capacity() const {
return p_buf.capacity() - 1; return p_buf.capacity() - 1;
} }
octa::Size length() const { Size length() const {
/* TODO: unicode */ /* TODO: unicode */
return size(); return size();
} }
@ -267,7 +267,7 @@ public:
return *this; return *this;
} }
StringBase &append(const StringBase &s, octa::Size idx, octa::Size len) { StringBase &append(const StringBase &s, Size idx, Size len) {
p_buf.pop(); p_buf.pop();
p_buf.insert_range(p_buf.size(), Range(&s[idx], p_buf.insert_range(p_buf.size(), Range(&s[idx],
(len == npos) ? (s.size() - idx) : len)); (len == npos) ? (s.size() - idx) : len));
@ -282,9 +282,9 @@ public:
return *this; return *this;
} }
StringBase &append(octa::Size n, T c) { StringBase &append(Size n, T c) {
p_buf.pop(); p_buf.pop();
for (octa::Size i = 0; i < n; ++i) p_buf.push(c); for (Size i = 0; i < n; ++i) p_buf.push(c);
p_buf.push('\0'); p_buf.push('\0');
return *this; return *this;
} }
@ -441,23 +441,21 @@ template<typename T> struct ToString {
template<typename U> template<typename U>
static String to_str(const U &v, static String to_str(const U &v,
octa::EnableIf<octa::detail::ToStringTest<U>::value, bool> = true EnableIf<detail::ToStringTest<U>::value, bool> = true
) { ) {
return v.to_string(); return v.to_string();
} }
template<typename U> template<typename U>
static String to_str(const U &v, static String to_str(const U &v,
octa::EnableIf<!octa::detail::ToStringTest<U>::value && EnableIf<!detail::ToStringTest<U>::value &&
!octa::IsScalar<U>::value, bool> = true !IsScalar<U>::value, bool> = true
) { ) {
String ret("{"); String ret("{");
ret += concat(octa::iter(v), ", ", ToString< ret += concat(octa::iter(v), ", ", ToString<
octa::RemoveCv< RemoveCv<RemoveReference<
octa::RemoveReference< RangeReference<decltype(octa::iter(v))>
octa::RangeReference<decltype(octa::iter(v))> >>
>
>
>()); >());
ret += "}"; ret += "}";
return ret; return ret;
@ -465,8 +463,8 @@ template<typename T> struct ToString {
template<typename U> template<typename U>
static String to_str(const U &v, static String to_str(const U &v,
octa::EnableIf<!octa::detail::ToStringTest<U>::value && EnableIf<!detail::ToStringTest<U>::value &&
octa::IsScalar<U>::value, bool> = true IsScalar<U>::value, bool> = true
) { ) {
return ToString<U>()(v); return ToString<U>()(v);
} }
@ -478,7 +476,7 @@ template<typename T> struct ToString {
namespace detail { namespace detail {
template<typename T> template<typename T>
void str_printf(octa::Vector<char> *s, const char *fmt, T v) { void str_printf(Vector<char> *s, const char *fmt, T v) {
char buf[256]; char buf[256];
int n = snprintf(buf, sizeof(buf), fmt, v); int n = snprintf(buf, sizeof(buf), fmt, v);
s->clear(); s->clear();
@ -491,7 +489,7 @@ namespace detail {
n = 0; n = 0;
*(s->data()) = '\0'; *(s->data()) = '\0';
} }
*((octa::Size *)s) = n + 1; *((Size *)s) = n + 1;
} }
} }
@ -519,24 +517,24 @@ template<> struct ToString<T> { \
using Result = String; \ using Result = String; \
String operator()(T v) { \ String operator()(T v) { \
String ret; \ String ret; \
octa::detail::str_printf((octa::Vector<char> *)&ret, fmt, v); \ detail::str_printf((Vector<char> *)&ret, fmt, v); \
return ret; \ return ret; \
} \ } \
}; };
OCTA_TOSTR_NUM(octa::sbyte, "%d") OCTA_TOSTR_NUM(sbyte, "%d")
OCTA_TOSTR_NUM(int, "%d") OCTA_TOSTR_NUM(int, "%d")
OCTA_TOSTR_NUM(int &, "%d") OCTA_TOSTR_NUM(int &, "%d")
OCTA_TOSTR_NUM(long, "%ld") OCTA_TOSTR_NUM(long, "%ld")
OCTA_TOSTR_NUM(float, "%f") OCTA_TOSTR_NUM(float, "%f")
OCTA_TOSTR_NUM(double, "%f") OCTA_TOSTR_NUM(double, "%f")
OCTA_TOSTR_NUM(octa::byte, "%u") OCTA_TOSTR_NUM(byte, "%u")
OCTA_TOSTR_NUM(octa::uint, "%u") OCTA_TOSTR_NUM(uint, "%u")
OCTA_TOSTR_NUM(octa::ulong, "%lu") OCTA_TOSTR_NUM(ulong, "%lu")
OCTA_TOSTR_NUM(octa::llong, "%lld") OCTA_TOSTR_NUM(llong, "%lld")
OCTA_TOSTR_NUM(octa::ullong, "%llu") OCTA_TOSTR_NUM(ullong, "%llu")
OCTA_TOSTR_NUM(octa::ldouble, "%Lf") OCTA_TOSTR_NUM(ldouble, "%Lf")
#undef OCTA_TOSTR_NUM #undef OCTA_TOSTR_NUM
@ -545,7 +543,7 @@ template<typename T> struct ToString<T *> {
using Result = String; using Result = String;
String operator()(Argument v) { String operator()(Argument v) {
String ret; String ret;
octa::detail::str_printf((octa::Vector<char> *)&ret, "%p", v); detail::str_printf((Vector<char> *)&ret, "%p", v);
return ret; return ret;
} }
}; };
@ -566,8 +564,8 @@ template<> struct ToString<StringRange> {
} }
}; };
template<typename T, typename U> struct ToString<octa::Pair<T, U>> { template<typename T, typename U> struct ToString<Pair<T, U>> {
using Argument = octa::Pair<T, U>; using Argument = Pair<T, U>;
using Result = String; using Result = String;
String operator()(const Argument &v) { String operator()(const Argument &v) {
String ret("{"); String ret("{");
@ -579,7 +577,7 @@ template<typename T, typename U> struct ToString<octa::Pair<T, U>> {
} }
}; };
template<typename T, typename = decltype(ToString<T>()(octa::declval<T>()))> template<typename T, typename = decltype(ToString<T>()(declval<T>()))>
String to_string(const T &v) { String to_string(const T &v) {
return ToString<T>()(v); return ToString<T>()(v);
} }

View File

@ -28,25 +28,25 @@ template<typename> struct IsReference;
template<typename> struct IsTriviallyDefaultConstructible; template<typename> struct IsTriviallyDefaultConstructible;
template<typename T> template<typename T>
using RemoveCv = typename octa::detail::RemoveCvBase<T>::Type; using RemoveCv = typename detail::RemoveCvBase<T>::Type;
template<typename T> template<typename T>
using AddLvalueReference = typename octa::detail::AddLr<T>::Type; using AddLvalueReference = typename detail::AddLr<T>::Type;
template<typename T> template<typename T>
using AddRvalueReference = typename octa::detail::AddRr<T>::Type; using AddRvalueReference = typename detail::AddRr<T>::Type;
template<typename T> template<typename T>
using AddConst = typename octa::detail::AddConstBase<T>::Type; using AddConst = typename detail::AddConstBase<T>::Type;
template<typename T> template<typename T>
using RemoveReference = typename octa::detail::RemoveReferenceBase<T>::Type; using RemoveReference = typename detail::RemoveReferenceBase<T>::Type;
template<typename T> template<typename T>
using RemoveAllExtents = typename octa::detail::RemoveAllExtentsBase<T>::Type; using RemoveAllExtents = typename detail::RemoveAllExtentsBase<T>::Type;
namespace detail { namespace detail {
template<typename T> octa::AddRvalueReference<T> declval_in(); template<typename T> AddRvalueReference<T> declval_in();
} }
/* integral constant */ /* integral constant */
@ -75,17 +75,17 @@ namespace detail {
} }
template<typename T> template<typename T>
struct IsVoid: octa::detail::IsVoidBase<RemoveCv<T>> {}; struct IsVoid: detail::IsVoidBase<RemoveCv<T>> {};
/* is null pointer */ /* is null pointer */
namespace detail { namespace detail {
template<typename> struct IsNullPointerBase : False {}; template<typename> struct IsNullPointerBase : False {};
template< > struct IsNullPointerBase<octa::Nullptr>: True {}; template< > struct IsNullPointerBase<Nullptr>: True {};
} }
template<typename T> struct IsNullPointer: template<typename T> struct IsNullPointer:
octa::detail::IsNullPointerBase<RemoveCv<T>> {}; detail::IsNullPointerBase<RemoveCv<T>> {};
/* is integer */ /* is integer */
@ -98,21 +98,21 @@ namespace detail {
template<> struct IsIntegralBase<int >: True {}; template<> struct IsIntegralBase<int >: True {};
template<> struct IsIntegralBase<long >: True {}; template<> struct IsIntegralBase<long >: True {};
template<> struct IsIntegralBase<octa::sbyte >: True {}; template<> struct IsIntegralBase<sbyte >: True {};
template<> struct IsIntegralBase<octa::byte >: True {}; template<> struct IsIntegralBase<byte >: True {};
template<> struct IsIntegralBase<octa::ushort>: True {}; template<> struct IsIntegralBase<ushort>: True {};
template<> struct IsIntegralBase<octa::uint >: True {}; template<> struct IsIntegralBase<uint >: True {};
template<> struct IsIntegralBase<octa::ulong >: True {}; template<> struct IsIntegralBase<ulong >: True {};
template<> struct IsIntegralBase<octa::llong >: True {}; template<> struct IsIntegralBase<llong >: True {};
template<> struct IsIntegralBase<octa::ullong>: True {}; template<> struct IsIntegralBase<ullong>: True {};
template<> struct IsIntegralBase<octa::Char16>: True {}; template<> struct IsIntegralBase<Char16>: True {};
template<> struct IsIntegralBase<octa::Char32>: True {}; template<> struct IsIntegralBase<Char32>: True {};
template<> struct IsIntegralBase<octa::Wchar >: True {}; template<> struct IsIntegralBase<Wchar >: True {};
} }
template<typename T> template<typename T>
struct IsIntegral: octa::detail::IsIntegralBase<RemoveCv<T>> {}; struct IsIntegral: detail::IsIntegralBase<RemoveCv<T>> {};
/* is floating point */ /* is floating point */
@ -122,17 +122,17 @@ namespace detail {
template<> struct IsFloatingPointBase<float >: True {}; template<> struct IsFloatingPointBase<float >: True {};
template<> struct IsFloatingPointBase<double>: True {}; template<> struct IsFloatingPointBase<double>: True {};
template<> struct IsFloatingPointBase<octa::ldouble>: True {}; template<> struct IsFloatingPointBase<ldouble>: True {};
} }
template<typename T> template<typename T>
struct IsFloatingPoint: octa::detail::IsFloatingPointBase<RemoveCv<T>> {}; struct IsFloatingPoint: detail::IsFloatingPointBase<RemoveCv<T>> {};
/* is array */ /* is array */
template<typename > struct IsArray : False {}; template<typename > struct IsArray : False {};
template<typename T > struct IsArray<T[] >: True {}; template<typename T > struct IsArray<T[] >: True {};
template<typename T, octa::Size N> struct IsArray<T[N]>: True {}; template<typename T, Size N> struct IsArray<T[N]>: True {};
/* is pointer */ /* is pointer */
@ -142,7 +142,7 @@ namespace detail {
} }
template<typename T> template<typename T>
struct IsPointer: octa::detail::IsPointerBase<RemoveCv<T>> {}; struct IsPointer: detail::IsPointerBase<RemoveCv<T>> {};
/* is lvalue reference */ /* is lvalue reference */
@ -178,11 +178,11 @@ namespace detail {
template<typename T> T &function_source(int); template<typename T> T &function_source(int);
template<typename T> FunctionTestDummy function_source(...); template<typename T> FunctionTestDummy function_source(...);
template<typename T, bool = octa::IsClass<T>::value || template<typename T, bool = IsClass<T>::value ||
octa::IsUnion<T>::value || IsUnion<T>::value ||
octa::IsVoid<T>::value || IsVoid<T>::value ||
octa::IsReference<T>::value || IsReference<T>::value ||
octa::IsNullPointer<T>::value IsNullPointer<T>::value
> struct IsFunctionBase: IntegralConstant<bool, > struct IsFunctionBase: IntegralConstant<bool,
sizeof(function_test<T>(function_source<T>(0))) == 1 sizeof(function_test<T>(function_source<T>(0))) == 1
> {}; > {};
@ -190,7 +190,7 @@ namespace detail {
template<typename T> struct IsFunctionBase<T, true>: False {}; template<typename T> struct IsFunctionBase<T, true>: False {};
} /* namespace detail */ } /* namespace detail */
template<typename T> struct IsFunction: octa::detail::IsFunctionBase<T> {}; template<typename T> struct IsFunction: detail::IsFunctionBase<T> {};
/* is arithmetic */ /* is arithmetic */
@ -221,7 +221,7 @@ namespace detail {
} }
template<typename T> template<typename T>
struct IsMemberPointer: octa::detail::IsMemberPointerBase<RemoveCv<T>> {}; struct IsMemberPointer: detail::IsMemberPointerBase<RemoveCv<T>> {};
/* is pointer to member object */ /* is pointer to member object */
@ -231,12 +231,12 @@ namespace detail {
template<typename T, typename U> template<typename T, typename U>
struct IsMemberObjectPointerBase<T U::*>: IntegralConstant<bool, struct IsMemberObjectPointerBase<T U::*>: IntegralConstant<bool,
!octa::IsFunction<T>::value !IsFunction<T>::value
> {}; > {};
} }
template<typename T> struct IsMemberObjectPointer: template<typename T> struct IsMemberObjectPointer:
octa::detail::IsMemberObjectPointerBase<RemoveCv<T>> {}; detail::IsMemberObjectPointerBase<RemoveCv<T>> {};
/* is pointer to member function */ /* is pointer to member function */
@ -246,12 +246,12 @@ namespace detail {
template<typename T, typename U> template<typename T, typename U>
struct IsMemberFunctionPointerBase<T U::*>: IntegralConstant<bool, struct IsMemberFunctionPointerBase<T U::*>: IntegralConstant<bool,
octa::IsFunction<T>::value IsFunction<T>::value
> {}; > {};
} }
template<typename T> struct IsMemberFunctionPointer: template<typename T> struct IsMemberFunctionPointer:
octa::detail::IsMemberFunctionPointerBase<RemoveCv<T>> {}; detail::IsMemberFunctionPointerBase<RemoveCv<T>> {};
/* is reference */ /* is reference */
@ -308,11 +308,11 @@ namespace detail {
struct IsSignedBase: IntegralConstant<bool, T(-1) < T(0)> {}; struct IsSignedBase: IntegralConstant<bool, T(-1) < T(0)> {};
} }
template<typename T, bool = octa::IsArithmetic<T>::value> template<typename T, bool = IsArithmetic<T>::value>
struct IsSigned: False {}; struct IsSigned: False {};
template<typename T> template<typename T>
struct IsSigned<T, true>: octa::detail::IsSignedBase<T> {}; struct IsSigned<T, true>: detail::IsSignedBase<T> {};
/* is unsigned */ /* is unsigned */
@ -321,11 +321,11 @@ namespace detail {
struct IsUnsignedBase: IntegralConstant<bool, T(0) < T(-1)> {}; struct IsUnsignedBase: IntegralConstant<bool, T(0) < T(-1)> {};
} }
template<typename T, bool = octa::IsArithmetic<T>::value> template<typename T, bool = IsArithmetic<T>::value>
struct IsUnsigned: False {}; struct IsUnsigned: False {};
template<typename T> template<typename T>
struct IsUnsigned<T, true>: octa::detail::IsUnsignedBase<T> {}; struct IsUnsigned<T, true>: detail::IsUnsignedBase<T> {};
/* is standard layout */ /* is standard layout */
@ -359,7 +359,7 @@ struct HasVirtualDestructor: IntegralConstant<bool,
/* is constructible */ /* is constructible */
namespace detail { namespace detail {
#define OCTA_MOVE(v) static_cast<octa::RemoveReference<decltype(v)> &&>(v) #define OCTA_MOVE(v) static_cast<RemoveReference<decltype(v)> &&>(v)
template<typename, typename T> struct Select2nd { using Type = T; }; template<typename, typename T> struct Select2nd { using Type = T; };
struct Any { Any(...); }; struct Any { Any(...); };
@ -383,7 +383,7 @@ namespace detail {
/* scalars are default constructible, refs are not */ /* scalars are default constructible, refs are not */
template<typename T> template<typename T>
struct CtibleCore<true, T>: octa::IsScalar<T> {}; struct CtibleCore<true, T>: IsScalar<T> {};
/* scalars and references are constructible from one arg if /* scalars and references are constructible from one arg if
* implicitly convertible to scalar or reference */ * implicitly convertible to scalar or reference */
@ -405,7 +405,7 @@ namespace detail {
/* treat scalars and refs separately */ /* treat scalars and refs separately */
template<bool, typename T, typename ...A> template<bool, typename T, typename ...A>
struct CtibleVoidCheck: CtibleCore< struct CtibleVoidCheck: CtibleCore<
(octa::IsScalar<T>::value || octa::IsReference<T>::value), T, A... (IsScalar<T>::value || IsReference<T>::value), T, A...
> {}; > {};
/* if any of T or A is void, IsConstructible should be false */ /* if any of T or A is void, IsConstructible should be false */
@ -418,23 +418,23 @@ namespace detail {
template<typename T, typename ...A> template<typename T, typename ...A>
struct CtibleContainsVoid<T, A...> { struct CtibleContainsVoid<T, A...> {
static constexpr bool value = octa::IsVoid<T>::value static constexpr bool value = IsVoid<T>::value
|| CtibleContainsVoid<A...>::value; || CtibleContainsVoid<A...>::value;
}; };
/* entry point */ /* entry point */
template<typename T, typename ...A> template<typename T, typename ...A>
struct Ctible: CtibleVoidCheck< struct Ctible: CtibleVoidCheck<
CtibleContainsVoid<T, A...>::value || octa::IsAbstract<T>::value, CtibleContainsVoid<T, A...>::value || IsAbstract<T>::value,
T, A... T, A...
> {}; > {};
/* array types are default constructible if their element type is */ /* array types are default constructible if their element type is */
template<typename T, octa::Size N> template<typename T, Size N>
struct CtibleCore<false, T[N]>: Ctible<octa::RemoveAllExtents<T>> {}; struct CtibleCore<false, T[N]>: Ctible<RemoveAllExtents<T>> {};
/* otherwise array types are not constructible by this syntax */ /* otherwise array types are not constructible by this syntax */
template<typename T, octa::Size N, typename ...A> template<typename T, Size N, typename ...A>
struct CtibleCore<false, T[N], A...>: False {}; struct CtibleCore<false, T[N], A...>: False {};
/* incomplete array types are not constructible */ /* incomplete array types are not constructible */
@ -443,7 +443,7 @@ namespace detail {
} /* namespace detail */ } /* namespace detail */
template<typename T, typename ...A> template<typename T, typename ...A>
struct IsConstructible: octa::detail::Ctible<T, A...> {}; struct IsConstructible: detail::Ctible<T, A...> {};
/* is default constructible */ /* is default constructible */
@ -464,14 +464,14 @@ template<typename T> struct IsMoveConstructible: IsConstructible<T,
/* is assignable */ /* is assignable */
namespace detail { namespace detail {
template<typename T, typename U> typename octa::detail::Select2nd< template<typename T, typename U> typename detail::Select2nd<
decltype((declval_in<T>() = declval_in<U>())), True decltype((declval_in<T>() = declval_in<U>())), True
>::Type assign_test(T &&, U &&); >::Type assign_test(T &&, U &&);
template<typename T> False assign_test(Any, T &&); template<typename T> False assign_test(Any, T &&);
template<typename T, typename U, bool = octa::IsVoid<T>::value || template<typename T, typename U, bool = IsVoid<T>::value ||
octa::IsVoid<U>::value IsVoid<U>::value
> struct IsAssignableBase: CommonTypeBase< > struct IsAssignableBase: CommonTypeBase<
decltype(assign_test(declval_in<T>(), declval_in<U>())) decltype(assign_test(declval_in<T>(), declval_in<U>()))
>::Type {}; >::Type {};
@ -481,7 +481,7 @@ namespace detail {
} /* namespace detail */ } /* namespace detail */
template<typename T, typename U> template<typename T, typename U>
struct IsAssignable: octa::detail::IsAssignableBase<T, U> {}; struct IsAssignable: detail::IsAssignableBase<T, U> {};
/* is copy assignable */ /* is copy assignable */
@ -504,7 +504,7 @@ namespace detail {
template<typename T> struct IsDestructorWellformed { template<typename T> struct IsDestructorWellformed {
template<typename TT> static char test(typename IsDtibleApply< template<typename TT> static char test(typename IsDtibleApply<
decltype(octa::detail::declval_in<TT &>().~TT()) decltype(detail::declval_in<TT &>().~TT())
>::Type); >::Type);
template<typename TT> static int test(...); template<typename TT> static int test(...);
@ -515,8 +515,8 @@ namespace detail {
template<typename, bool> struct DtibleImpl; template<typename, bool> struct DtibleImpl;
template<typename T> template<typename T>
struct DtibleImpl<T, false>: octa::IntegralConstant<bool, struct DtibleImpl<T, false>: IntegralConstant<bool,
IsDestructorWellformed<octa::RemoveAllExtents<T>>::value IsDestructorWellformed<RemoveAllExtents<T>>::value
> {}; > {};
template<typename T> template<typename T>
@ -525,13 +525,13 @@ namespace detail {
template<typename T, bool> struct DtibleFalse; template<typename T, bool> struct DtibleFalse;
template<typename T> struct DtibleFalse<T, false> template<typename T> struct DtibleFalse<T, false>
: DtibleImpl<T, octa::IsReference<T>::value> {}; : DtibleImpl<T, IsReference<T>::value> {};
template<typename T> struct DtibleFalse<T, true>: False {}; template<typename T> struct DtibleFalse<T, true>: False {};
} /* namespace detail */ } /* namespace detail */
template<typename T> template<typename T>
struct IsDestructible: octa::detail::DtibleFalse<T, IsFunction<T>::value> {}; struct IsDestructible: detail::DtibleFalse<T, IsFunction<T>::value> {};
template<typename T> struct IsDestructible<T[]>: False {}; template<typename T> struct IsDestructible<T[]>: False {};
template< > struct IsDestructible<void>: False {}; template< > struct IsDestructible<void>: False {};
@ -634,10 +634,10 @@ struct IsBaseOf: IntegralConstant<bool, __is_base_of(B, D)> {};
/* is convertible */ /* is convertible */
namespace detail { namespace detail {
template<typename F, typename T, bool = octa::IsVoid<F>::value template<typename F, typename T, bool = IsVoid<F>::value
|| octa::IsFunction<T>::value || octa::IsArray<T>::value || IsFunction<T>::value || IsArray<T>::value
> struct IsConvertibleBase { > struct IsConvertibleBase {
using Type = typename octa::IsVoid<T>::Type; using Type = typename IsVoid<T>::Type;
}; };
template<typename F, typename T> template<typename F, typename T>
@ -646,16 +646,16 @@ namespace detail {
template<typename FF, typename TT, template<typename FF, typename TT,
typename = decltype(test_f<TT>(declval_in<FF>())) typename = decltype(test_f<TT>(declval_in<FF>()))
> static octa::True test(int); > static True test(int);
template<typename, typename> static octa::False test(...); template<typename, typename> static False test(...);
using Type = decltype(test<F, T>(0)); using Type = decltype(test<F, T>(0));
}; };
} }
template<typename F, typename T> template<typename F, typename T>
struct IsConvertible: octa::detail::IsConvertibleBase<F, T>::Type {}; struct IsConvertible: detail::IsConvertibleBase<F, T>::Type {};
/* type equality */ /* type equality */
@ -664,30 +664,30 @@ template<typename T > struct IsSame<T, T>: True {};
/* extent */ /* extent */
template<typename T, octa::uint I = 0> template<typename T, uint I = 0>
struct Extent: IntegralConstant<octa::Size, 0> {}; struct Extent: IntegralConstant<Size, 0> {};
template<typename T> template<typename T>
struct Extent<T[], 0>: IntegralConstant<octa::Size, 0> {}; struct Extent<T[], 0>: IntegralConstant<Size, 0> {};
template<typename T, octa::uint I> template<typename T, uint I>
struct Extent<T[], I>: IntegralConstant<octa::Size, Extent<T, I - 1>::value> {}; struct Extent<T[], I>: IntegralConstant<Size, Extent<T, I - 1>::value> {};
template<typename T, octa::Size N> template<typename T, Size N>
struct Extent<T[N], 0>: IntegralConstant<octa::Size, N> {}; struct Extent<T[N], 0>: IntegralConstant<Size, N> {};
template<typename T, octa::Size N, octa::uint I> template<typename T, Size N, uint I>
struct Extent<T[N], I>: IntegralConstant<octa::Size, Extent<T, I - 1>::value> {}; struct Extent<T[N], I>: IntegralConstant<Size, Extent<T, I - 1>::value> {};
/* rank */ /* rank */
template<typename T> struct Rank: IntegralConstant<octa::Size, 0> {}; template<typename T> struct Rank: IntegralConstant<Size, 0> {};
template<typename T> template<typename T>
struct Rank<T[]>: IntegralConstant<octa::Size, Rank<T>::value + 1> {}; struct Rank<T[]>: IntegralConstant<Size, Rank<T>::value + 1> {};
template<typename T, octa::Size N> template<typename T, Size N>
struct Rank<T[N]>: IntegralConstant<octa::Size, Rank<T>::value + 1> {}; struct Rank<T[N]>: IntegralConstant<Size, Rank<T>::value + 1> {};
/* remove const, volatile, cv */ /* remove const, volatile, cv */
@ -704,22 +704,22 @@ namespace detail {
} }
template<typename T> template<typename T>
using RemoveConst = typename octa::detail::RemoveConstBase<T>::Type; using RemoveConst = typename detail::RemoveConstBase<T>::Type;
template<typename T> template<typename T>
using RemoveVolatile = typename octa::detail::RemoveVolatileBase<T>::Type; using RemoveVolatile = typename detail::RemoveVolatileBase<T>::Type;
namespace detail { namespace detail {
template<typename T> template<typename T>
struct RemoveCvBase { struct RemoveCvBase {
using Type = octa::RemoveVolatile<octa::RemoveConst<T>>; using Type = RemoveVolatile<RemoveConst<T>>;
}; };
} }
/* add const, volatile, cv */ /* add const, volatile, cv */
namespace detail { namespace detail {
template<typename T, bool = octa::IsReference<T>::value template<typename T, bool = IsReference<T>::value
|| octa::IsFunction<T>::value || octa::IsConst<T>::value> || IsFunction<T>::value || IsConst<T>::value>
struct AddConstCore { using Type = T; }; struct AddConstCore { using Type = T; };
template<typename T> struct AddConstCore<T, false> { template<typename T> struct AddConstCore<T, false> {
@ -730,8 +730,8 @@ namespace detail {
using Type = typename AddConstCore<T>::Type; using Type = typename AddConstCore<T>::Type;
}; };
template<typename T, bool = octa::IsReference<T>::value template<typename T, bool = IsReference<T>::value
|| octa::IsFunction<T>::value || octa::IsVolatile<T>::value> || IsFunction<T>::value || IsVolatile<T>::value>
struct AddVolatileCore { using Type = T; }; struct AddVolatileCore { using Type = T; };
template<typename T> struct AddVolatileCore<T, false> { template<typename T> struct AddVolatileCore<T, false> {
@ -744,17 +744,17 @@ namespace detail {
} }
template<typename T> template<typename T>
using AddVolatile = typename octa::detail::AddVolatileBase<T>::Type; using AddVolatile = typename detail::AddVolatileBase<T>::Type;
namespace detail { namespace detail {
template<typename T> template<typename T>
struct AddCvBase { struct AddCvBase {
using Type = octa::AddConst<octa::AddVolatile<T>>; using Type = AddConst<AddVolatile<T>>;
}; };
} }
template<typename T> template<typename T>
using AddCv = typename octa::detail::AddCvBase<T>::Type; using AddCv = typename detail::AddCvBase<T>::Type;
/* remove reference */ /* remove reference */
@ -783,18 +783,18 @@ namespace detail {
} }
template<typename T> template<typename T>
using RemovePointer = typename octa::detail::RemovePointerBase<T>::Type; using RemovePointer = typename detail::RemovePointerBase<T>::Type;
/* add pointer */ /* add pointer */
namespace detail { namespace detail {
template<typename T> struct AddPointerBase { template<typename T> struct AddPointerBase {
using Type = octa::RemoveReference<T> *; using Type = RemoveReference<T> *;
}; };
} }
template<typename T> template<typename T>
using AddPointer = typename octa::detail::AddPointerBase<T>::Type; using AddPointer = typename detail::AddPointerBase<T>::Type;
/* add lvalue reference */ /* add lvalue reference */
@ -843,12 +843,12 @@ namespace detail {
struct RemoveExtentBase { using Type = T; }; struct RemoveExtentBase { using Type = T; };
template<typename T> template<typename T>
struct RemoveExtentBase<T[ ]> { using Type = T; }; struct RemoveExtentBase<T[ ]> { using Type = T; };
template<typename T, octa::Size N> template<typename T, Size N>
struct RemoveExtentBase<T[N]> { using Type = T; }; struct RemoveExtentBase<T[N]> { using Type = T; };
} }
template<typename T> template<typename T>
using RemoveExtent = typename octa::detail::RemoveExtentBase<T>::Type; using RemoveExtent = typename detail::RemoveExtentBase<T>::Type;
/* remove all extents */ /* remove all extents */
@ -859,7 +859,7 @@ namespace detail {
using Type = RemoveAllExtentsBase<T>; using Type = RemoveAllExtentsBase<T>;
}; };
template<typename T, octa::Size N> struct RemoveAllExtentsBase<T[N]> { template<typename T, Size N> struct RemoveAllExtentsBase<T[N]> {
using Type = RemoveAllExtentsBase<T>; using Type = RemoveAllExtentsBase<T>;
}; };
} }
@ -884,34 +884,34 @@ namespace detail {
~TlNat() = delete; ~TlNat() = delete;
}; };
using Stypes = TypeList<octa::sbyte, using Stypes = TypeList<sbyte,
TypeList<short, TypeList<short,
TypeList<int, TypeList<int,
TypeList<long, TypeList<long,
TypeList<octa::llong, TlNat>>>>>; TypeList<llong, TlNat>>>>>;
using Utypes = TypeList<octa::byte, using Utypes = TypeList<byte,
TypeList<octa::ushort, TypeList<ushort,
TypeList<octa::uint, TypeList<uint,
TypeList<octa::ulong, TypeList<ulong,
TypeList<octa::ullong, TlNat>>>>>; TypeList<ullong, TlNat>>>>>;
template<typename T, octa::Size N, bool = (N <= sizeof(typename T::First))> template<typename T, Size N, bool = (N <= sizeof(typename T::First))>
struct TypeFindFirst; struct TypeFindFirst;
template<typename T, typename U, octa::Size N> template<typename T, typename U, Size N>
struct TypeFindFirst<TypeList<T, U>, N, true> { struct TypeFindFirst<TypeList<T, U>, N, true> {
using Type = T; using Type = T;
}; };
template<typename T, typename U, octa::Size N> template<typename T, typename U, Size N>
struct TypeFindFirst<TypeList<T, U>, N, false> { struct TypeFindFirst<TypeList<T, U>, N, false> {
using Type = typename TypeFindFirst<U, N>::Type; using Type = typename TypeFindFirst<U, N>::Type;
}; };
template<typename T, typename U, template<typename T, typename U,
bool = octa::IsConst<octa::RemoveReference<T>>::value, bool = IsConst<RemoveReference<T>>::value,
bool = octa::IsVolatile<octa::RemoveReference<T>>::value bool = IsVolatile<RemoveReference<T>>::value
> struct ApplyCv { > struct ApplyCv {
using Type = U; using Type = U;
}; };
@ -946,67 +946,67 @@ namespace detail {
using Type = const volatile U &; using Type = const volatile U &;
}; };
template<typename T, bool = octa::IsIntegral<T>::value || template<typename T, bool = IsIntegral<T>::value ||
octa::IsEnum<T>::value> IsEnum<T>::value>
struct MakeSigned {}; struct MakeSignedCore {};
template<typename T, bool = octa::IsIntegral<T>::value || template<typename T, bool = IsIntegral<T>::value ||
octa::IsEnum<T>::value> IsEnum<T>::value>
struct MakeUnsigned {}; struct MakeUnsignedCore {};
template<typename T> template<typename T>
struct MakeSigned<T, true> { struct MakeSignedCore<T, true> {
using Type = typename TypeFindFirst<Stypes, sizeof(T)>::Type; using Type = typename TypeFindFirst<Stypes, sizeof(T)>::Type;
}; };
template<typename T> template<typename T>
struct MakeUnsigned<T, true> { struct MakeUnsignedCore<T, true> {
using Type = typename TypeFindFirst<Utypes, sizeof(T)>::Type; using Type = typename TypeFindFirst<Utypes, sizeof(T)>::Type;
}; };
template<> struct MakeSigned<bool , true> {}; template<> struct MakeSignedCore<bool , true> {};
template<> struct MakeSigned<short , true> { using Type = short; }; template<> struct MakeSignedCore<short , true> { using Type = short; };
template<> struct MakeSigned<int , true> { using Type = int; }; template<> struct MakeSignedCore<int , true> { using Type = int; };
template<> struct MakeSigned<long , true> { using Type = long; }; template<> struct MakeSignedCore<long , true> { using Type = long; };
template<> struct MakeSigned<octa::sbyte , true> { using Type = octa::sbyte; }; template<> struct MakeSignedCore<sbyte , true> { using Type = sbyte; };
template<> struct MakeSigned<octa::byte , true> { using Type = octa::sbyte; }; template<> struct MakeSignedCore<byte , true> { using Type = sbyte; };
template<> struct MakeSigned<octa::ushort, true> { using Type = short; }; template<> struct MakeSignedCore<ushort, true> { using Type = short; };
template<> struct MakeSigned<octa::uint , true> { using Type = int; }; template<> struct MakeSignedCore<uint , true> { using Type = int; };
template<> struct MakeSigned<octa::ulong , true> { using Type = long; }; template<> struct MakeSignedCore<ulong , true> { using Type = long; };
template<> struct MakeSigned<octa::llong , true> { using Type = octa::llong; }; template<> struct MakeSignedCore<llong , true> { using Type = llong; };
template<> struct MakeSigned<octa::ullong, true> { using Type = octa::llong; }; template<> struct MakeSignedCore<ullong, true> { using Type = llong; };
template<> struct MakeUnsigned<bool , true> {}; template<> struct MakeUnsignedCore<bool , true> {};
template<> struct MakeUnsigned<short , true> { using Type = octa::ushort; }; template<> struct MakeUnsignedCore<short , true> { using Type = ushort; };
template<> struct MakeUnsigned<int , true> { using Type = octa::uint; }; template<> struct MakeUnsignedCore<int , true> { using Type = uint; };
template<> struct MakeUnsigned<long , true> { using Type = octa::ulong; }; template<> struct MakeUnsignedCore<long , true> { using Type = ulong; };
template<> struct MakeUnsigned<octa::sbyte , true> { using Type = octa::byte; }; template<> struct MakeUnsignedCore<sbyte , true> { using Type = byte; };
template<> struct MakeUnsigned<octa::byte , true> { using Type = octa::byte; }; template<> struct MakeUnsignedCore<byte , true> { using Type = byte; };
template<> struct MakeUnsigned<octa::ushort, true> { using Type = octa::ushort; }; template<> struct MakeUnsignedCore<ushort, true> { using Type = ushort; };
template<> struct MakeUnsigned<octa::uint , true> { using Type = octa::uint; }; template<> struct MakeUnsignedCore<uint , true> { using Type = uint; };
template<> struct MakeUnsigned<octa::ulong , true> { using Type = octa::ulong; }; template<> struct MakeUnsignedCore<ulong , true> { using Type = ulong; };
template<> struct MakeUnsigned<octa::llong , true> { using Type = octa::ullong; }; template<> struct MakeUnsignedCore<llong , true> { using Type = ullong; };
template<> struct MakeUnsigned<octa::ullong, true> { using Type = octa::ullong; }; template<> struct MakeUnsignedCore<ullong, true> { using Type = ullong; };
template<typename T> struct MakeSignedBase { template<typename T> struct MakeSignedBase {
using Type = typename ApplyCv<T, using Type = typename ApplyCv<T,
typename MakeSigned<octa::RemoveCv<T>>::Type typename MakeSignedCore<RemoveCv<T>>::Type
>::Type; >::Type;
}; };
template<typename T> struct MakeUnsignedBase { template<typename T> struct MakeUnsignedBase {
using Type = typename ApplyCv<T, using Type = typename ApplyCv<T,
typename MakeUnsigned<octa::RemoveCv<T>>::Type typename MakeUnsignedCore<RemoveCv<T>>::Type
>::Type; >::Type;
}; };
} /* namespace detail */ } /* namespace detail */
template<typename T> template<typename T>
using MakeSigned = typename octa::detail::MakeSignedBase<T>::Type; using MakeSigned = typename detail::MakeSignedBase<T>::Type;
template<typename T> template<typename T>
using MakeUnsigned = typename octa::detail::MakeUnsignedBase<T>::Type; using MakeUnsigned = typename detail::MakeUnsignedBase<T>::Type;
/* conditional */ /* conditional */
@ -1023,7 +1023,7 @@ namespace detail {
} }
template<bool _cond, typename T, typename U> template<bool _cond, typename T, typename U>
using Conditional = typename octa::detail::ConditionalBase<_cond, T, U>::Type; using Conditional = typename detail::ConditionalBase<_cond, T, U>::Type;
/* result of call at compile time */ /* result of call at compile time */
@ -1062,16 +1062,16 @@ namespace detail {
struct ResultOfCore {}; struct ResultOfCore {};
template<typename F, typename ...A> template<typename F, typename ...A>
struct ResultOfCore<F(A...), decltype(void(rof_invoke( struct ResultOfCore<F(A...), decltype(void(rof_invoke(
octa::detail::declval_in<F>(), octa::detail::declval_in<A>()...)))> { detail::declval_in<F>(), detail::declval_in<A>()...)))> {
using type = decltype(rof_invoke(octa::detail::declval_in<F>(), using type = decltype(rof_invoke(detail::declval_in<F>(),
octa::detail::declval_in<A>()...)); detail::declval_in<A>()...));
}; };
template<typename T> struct ResultOfBase: ResultOfCore<T> {}; template<typename T> struct ResultOfBase: ResultOfCore<T> {};
} /* namespace detail */ } /* namespace detail */
template<typename T> template<typename T>
using ResultOf = typename octa::detail::ResultOfBase<T>::Type; using ResultOf = typename detail::ResultOfBase<T>::Type;
/* enable if */ /* enable if */
@ -1082,7 +1082,7 @@ namespace detail {
} }
template<bool B, typename T = void> template<bool B, typename T = void>
using EnableIf = typename octa::detail::EnableIfBase<B, T>::Type; using EnableIf = typename detail::EnableIfBase<B, T>::Type;
/* decay */ /* decay */
@ -1090,18 +1090,18 @@ namespace detail {
template<typename T> template<typename T>
struct DecayBase { struct DecayBase {
private: private:
using U = octa::RemoveReference<T>; using U = RemoveReference<T>;
public: public:
using Type = octa::Conditional<octa::IsArray<U>::value, using Type = Conditional<IsArray<U>::value,
octa::RemoveExtent<U> *, RemoveExtent<U> *,
octa::Conditional<octa::IsFunction<U>::value, Conditional<IsFunction<U>::value,
octa::AddPointer<U>, octa::RemoveCv<U>> AddPointer<U>, RemoveCv<U>>
>; >;
}; };
} }
template<typename T> template<typename T>
using Decay = typename octa::detail::DecayBase<T>::Type; using Decay = typename detail::DecayBase<T>::Type;
/* common type */ /* common type */
@ -1113,8 +1113,8 @@ namespace detail {
}; };
template<typename T, typename U> struct CommonTypeBase<T, U> { template<typename T, typename U> struct CommonTypeBase<T, U> {
using Type = Decay<decltype(true ? octa::detail::declval_in<T>() using Type = Decay<decltype(true ? detail::declval_in<T>()
: octa::detail::declval_in<U>())>; : detail::declval_in<U>())>;
}; };
template<typename T, typename U, typename ...V> template<typename T, typename U, typename ...V>
@ -1126,61 +1126,61 @@ namespace detail {
} }
template<typename T, typename U, typename ...V> template<typename T, typename U, typename ...V>
using CommonType = typename octa::detail::CommonTypeBase<T, U, V...>::Type; using CommonType = typename detail::CommonTypeBase<T, U, V...>::Type;
/* aligned storage */ /* aligned storage */
namespace detail { namespace detail {
template<octa::Size N> struct AlignedTest { template<Size N> struct AlignedTest {
union Type { union Type {
octa::byte data[N]; byte data[N];
octa::MaxAlign align; MaxAlign align;
}; };
}; };
template<octa::Size N, octa::Size A> struct AlignedStorageBase { template<Size N, Size A> struct AlignedStorageBase {
struct Type { struct Type {
alignas(A) octa::byte data[N]; alignas(A) byte data[N];
}; };
}; };
} }
template<octa::Size N, octa::Size A template<Size N, Size A
= alignof(typename octa::detail::AlignedTest<N>::Type) = alignof(typename detail::AlignedTest<N>::Type)
> using AlignedStorage = typename octa::detail::AlignedStorageBase<N, A>::Type; > using AlignedStorage = typename detail::AlignedStorageBase<N, A>::Type;
/* aligned union */ /* aligned union */
namespace detail { namespace detail {
template<octa::Size ...N> struct AlignMax; template<Size ...N> struct AlignMax;
template<octa::Size N> struct AlignMax<N> { template<Size N> struct AlignMax<N> {
static constexpr octa::Size value = N; static constexpr Size value = N;
}; };
template<octa::Size N1, octa::Size N2> struct AlignMax<N1, N2> { template<Size N1, Size N2> struct AlignMax<N1, N2> {
static constexpr octa::Size value = (N1 > N2) ? N1 : N2; static constexpr Size value = (N1 > N2) ? N1 : N2;
}; };
template<octa::Size N1, octa::Size N2, octa::Size ...N> template<Size N1, Size N2, Size ...N>
struct AlignMax<N1, N2, N...> { struct AlignMax<N1, N2, N...> {
static constexpr octa::Size value static constexpr Size value
= AlignMax<AlignMax<N1, N2>::value, N...>::value; = AlignMax<AlignMax<N1, N2>::value, N...>::value;
}; };
template<octa::Size N, typename ...T> struct AlignedUnionBase { template<Size N, typename ...T> struct AlignedUnionBase {
static constexpr octa::Size alignment_value static constexpr Size alignment_value
= AlignMax<alignof(T)...>::value; = AlignMax<alignof(T)...>::value;
struct type { struct type {
alignas(alignment_value) octa::byte data[AlignMax<N, alignas(alignment_value) byte data[AlignMax<N,
sizeof(T)...>::value]; sizeof(T)...>::value];
}; };
}; };
} /* namespace detail */ } /* namespace detail */
template<octa::Size N, typename ...T> template<Size N, typename ...T>
using AlignedUnion = typename octa::detail::AlignedUnionBase<N, T...>::Type; using AlignedUnion = typename detail::AlignedUnionBase<N, T...>::Type;
/* underlying type */ /* underlying type */
@ -1192,7 +1192,7 @@ namespace detail {
} }
template<typename T> template<typename T>
using UnderlyingType = typename octa::detail::UnderlyingTypeBase<T>::Type; using UnderlyingType = typename detail::UnderlyingTypeBase<T>::Type;
} /* namespace octa */ } /* namespace octa */
#endif #endif

View File

@ -56,26 +56,26 @@ namespace detail {
}; };
template<typename T> inline void swap(T &a, T &b, EnableIf< template<typename T> inline void swap(T &a, T &b, EnableIf<
octa::detail::SwapTest<T>::value, bool detail::SwapTest<T>::value, bool
> = true) { > = true) {
a.swap(b); a.swap(b);
} }
template<typename T> inline void swap(T &a, T &b, EnableIf< template<typename T> inline void swap(T &a, T &b, EnableIf<
!octa::detail::SwapTest<T>::value, bool !detail::SwapTest<T>::value, bool
> = true) { > = true) {
T c(octa::move(a)); T c(move(a));
a = octa::move(b); a = move(b);
b = octa::move(c); b = move(c);
} }
} }
template<typename T> void swap(T &a, T &b) { template<typename T> void swap(T &a, T &b) {
octa::detail::swap(a, b); detail::swap(a, b);
} }
template<typename T, octa::Size N> void swap(T (&a)[N], T (&b)[N]) { template<typename T, Size N> void swap(T (&a)[N], T (&b)[N]) {
for (octa::Size i = 0; i < N; ++i) { for (Size i = 0; i < N; ++i) {
octa::swap(a[i], b[i]); octa::swap(a[i], b[i]);
} }
} }
@ -97,14 +97,14 @@ struct Pair {
template<typename TT, typename UU> template<typename TT, typename UU>
Pair(TT &&x, UU &&y): Pair(TT &&x, UU &&y):
first(octa::forward<TT>(x)), second(octa::forward<UU>(y)) {} first(forward<TT>(x)), second(forward<UU>(y)) {}
template<typename TT, typename UU> template<typename TT, typename UU>
Pair(const Pair<TT, UU> &v): first(v.first), second(v.second) {} Pair(const Pair<TT, UU> &v): first(v.first), second(v.second) {}
template<typename TT, typename UU> template<typename TT, typename UU>
Pair(Pair<TT, UU> &&v): Pair(Pair<TT, UU> &&v):
first(octa::move(v.first)), second(octa::move(v.second)) {} first(move(v.first)), second(move(v.second)) {}
Pair &operator=(const Pair &v) { Pair &operator=(const Pair &v) {
first = v.first; first = v.first;
@ -120,21 +120,21 @@ struct Pair {
} }
Pair &operator=(Pair &&v) { Pair &operator=(Pair &&v) {
first = octa::move(v.first); first = move(v.first);
second = octa::move(v.second); second = move(v.second);
return *this; return *this;
} }
template<typename TT, typename UU> template<typename TT, typename UU>
Pair &operator=(Pair<TT, UU> &&v) { Pair &operator=(Pair<TT, UU> &&v) {
first = octa::forward<TT>(v.first); first = forward<TT>(v.first);
second = octa::forward<UU>(v.second); second = forward<UU>(v.second);
return *this; return *this;
} }
void swap(Pair &v) { void swap(Pair &v) {
octa::swap(first, v.first); swap(first, v.first);
octa::swap(second, v.second); swap(second, v.second);
} }
}; };
@ -153,24 +153,24 @@ namespace detail {
template<typename T> template<typename T>
struct MakePairRet { struct MakePairRet {
using Type = typename octa::detail::MakePairRetBase<octa::Decay<T>>::Type; using Type = typename detail::MakePairRetBase<Decay<T>>::Type;
}; };
} /* namespace detail */ } /* namespace detail */
template<typename T, typename U> template<typename T, typename U>
Pair<typename octa::detail::MakePairRet<T>::Type, Pair<typename detail::MakePairRet<T>::Type,
typename octa::detail::MakePairRet<U>::Type typename detail::MakePairRet<U>::Type
> make_pair(T &&a, U &&b) { > make_pair(T &&a, U &&b) {
return Pair<typename octa::detail::MakePairRet<T>::Type, return Pair<typename detail::MakePairRet<T>::Type,
typename octa::detail::MakePairRet<U>::Type typename detail::MakePairRet<U>::Type
>(forward<T>(a), forward<U>(b));; >(forward<T>(a), forward<U>(b));;
} }
namespace detail { namespace detail {
template<typename T, typename U, template<typename T, typename U,
bool = octa::IsSame<octa::RemoveCv<T>, octa::RemoveCv<U>>::value, bool = IsSame<RemoveCv<T>, RemoveCv<U>>::value,
bool = octa::IsEmpty<T>::value, bool = IsEmpty<T>::value,
bool = octa::IsEmpty<U>::value bool = IsEmpty<U>::value
> struct CompressedPairSwitch; > struct CompressedPairSwitch;
/* neither empty */ /* neither empty */
@ -193,7 +193,7 @@ namespace detail {
template<typename T, typename U> template<typename T, typename U>
struct CompressedPairSwitch<T, U, true, true, true> { enum { value = 1 }; }; struct CompressedPairSwitch<T, U, true, true, true> { enum { value = 1 }; };
template<typename T, typename U, octa::Size = CompressedPairSwitch<T, U>::value> template<typename T, typename U, Size = CompressedPairSwitch<T, U>::value>
struct CompressedPairBase; struct CompressedPairBase;
template<typename T, typename U> template<typename T, typename U>
@ -202,8 +202,8 @@ namespace detail {
U p_second; U p_second;
template<typename TT, typename UU> template<typename TT, typename UU>
CompressedPairBase(TT &&a, UU &&b): p_first(octa::forward<TT>(a)), CompressedPairBase(TT &&a, UU &&b): p_first(forward<TT>(a)),
p_second(octa::forward<UU>(b)) {} p_second(forward<UU>(b)) {}
T &first() { return p_first; } T &first() { return p_first; }
const T &first() const { return p_first; } const T &first() const { return p_first; }
@ -222,8 +222,8 @@ namespace detail {
U p_second; U p_second;
template<typename TT, typename UU> template<typename TT, typename UU>
CompressedPairBase(TT &&a, UU &&b): T(octa::forward<TT>(a)), CompressedPairBase(TT &&a, UU &&b): T(forward<TT>(a)),
p_second(octa::forward<UU>(b)) {} p_second(forward<UU>(b)) {}
T &first() { return *this; } T &first() { return *this; }
const T &first() const { return *this; } const T &first() const { return *this; }
@ -241,8 +241,8 @@ namespace detail {
T p_first; T p_first;
template<typename TT, typename UU> template<typename TT, typename UU>
CompressedPairBase(TT &&a, UU &&b): U(octa::forward<UU>(b)), CompressedPairBase(TT &&a, UU &&b): U(forward<UU>(b)),
p_first(octa::forward<TT>(a)) {} p_first(forward<TT>(a)) {}
T &first() { return p_first; } T &first() { return p_first; }
const T &first() const { return p_first; } const T &first() const { return p_first; }
@ -258,8 +258,8 @@ namespace detail {
template<typename T, typename U> template<typename T, typename U>
struct CompressedPairBase<T, U, 3>: T, U { struct CompressedPairBase<T, U, 3>: T, U {
template<typename TT, typename UU> template<typename TT, typename UU>
CompressedPairBase(TT &&a, UU &&b): T(octa::forward<TT>(a)), CompressedPairBase(TT &&a, UU &&b): T(forward<TT>(a)),
U(octa::forward<UU>(b)) {} U(forward<UU>(b)) {}
T &first() { return *this; } T &first() { return *this; }
const T &first() const { return *this; } const T &first() const { return *this; }
@ -275,8 +275,8 @@ namespace detail {
using Base = CompressedPairBase<T, U>; using Base = CompressedPairBase<T, U>;
template<typename TT, typename UU> template<typename TT, typename UU>
CompressedPair(TT &&a, UU &&b): Base(octa::forward<TT>(a), CompressedPair(TT &&a, UU &&b): Base(forward<TT>(a),
octa::forward<UU>(b)) {} forward<UU>(b)) {}
T &first() { return Base::first(); } T &first() { return Base::first(); }
const T &first() const { return Base::first(); } const T &first() const { return Base::first(); }

View File

@ -21,28 +21,28 @@ namespace octa {
namespace detail { namespace detail {
} /* namespace detail */ } /* namespace detail */
template<typename T, typename A = octa::Allocator<T>> template<typename T, typename A = Allocator<T>>
class Vector { class Vector {
using VecPair = octa::detail::CompressedPair<octa::AllocatorPointer<A>, A>; using VecPair = detail::CompressedPair<AllocatorPointer<A>, A>;
octa::Size p_len, p_cap; Size p_len, p_cap;
VecPair p_buf; VecPair p_buf;
void insert_base(octa::Size idx, octa::Size n) { void insert_base(Size idx, Size n) {
if (p_len + n > p_cap) reserve(p_len + n); if (p_len + n > p_cap) reserve(p_len + n);
p_len += n; p_len += n;
for (octa::Size i = p_len - 1; i > idx + n - 1; --i) { for (Size i = p_len - 1; i > idx + n - 1; --i) {
p_buf.first()[i] = octa::move(p_buf.first()[i - n]); p_buf.first()[i] = move(p_buf.first()[i - n]);
} }
} }
template<typename R> template<typename R>
void ctor_from_range(R &range, octa::EnableIf< void ctor_from_range(R &range, EnableIf<
octa::IsFiniteRandomAccessRange<R>::value && IsFiniteRandomAccessRange<R>::value &&
octa::IsPod<T>::value && IsPod<T>::value &&
octa::IsSame<T, octa::RemoveCv<octa::RangeValue<R>>>::value, bool IsSame<T, RemoveCv<RangeValue<R>>>::value, bool
> = true) { > = true) {
octa::RangeSize<R> l = range.size(); RangeSize<R> l = range.size();
reserve(l); reserve(l);
p_len = l; p_len = l;
range.copy(p_buf.first(), l); range.copy(p_buf.first(), l);
@ -50,58 +50,57 @@ class Vector {
template<typename R> template<typename R>
void ctor_from_range(R &range, EnableIf< void ctor_from_range(R &range, EnableIf<
!octa::IsFiniteRandomAccessRange<R>::value || !IsFiniteRandomAccessRange<R>::value ||
!octa::IsPod<T>::value || !IsPod<T>::value ||
!octa::IsSame<T, octa::RemoveCv<octa::RangeValue<R>>>::value, bool !IsSame<T, RemoveCv<RangeValue<R>>>::value, bool
> = true) { > = true) {
octa::Size i = 0; Size i = 0;
for (; !range.empty(); range.pop_front()) { for (; !range.empty(); range.pop_front()) {
reserve(i + 1); reserve(i + 1);
octa::allocator_construct(p_buf.second(), allocator_construct(p_buf.second(), &p_buf.first()[i],
&p_buf.first()[i], range.front()); range.front());
++i; ++i;
p_len = i; p_len = i;
} }
} }
void copy_contents(const Vector &v) { void copy_contents(const Vector &v) {
if (octa::IsPod<T>()) { if (IsPod<T>()) {
memcpy(p_buf.first(), v.p_buf.first(), p_len * sizeof(T)); memcpy(p_buf.first(), v.p_buf.first(), p_len * sizeof(T));
} else { } else {
Pointer cur = p_buf.first(), last = p_buf.first() + p_len; Pointer cur = p_buf.first(), last = p_buf.first() + p_len;
Pointer vbuf = v.p_buf.first(); Pointer vbuf = v.p_buf.first();
while (cur != last) { while (cur != last) {
octa::allocator_construct(p_buf.second(), allocator_construct(p_buf.second(), cur++, *vbuf++);
cur++, *vbuf++);
} }
} }
} }
public: public:
using Size = octa::Size; using Size = Size;
using Difference = octa::Ptrdiff; using Difference = Ptrdiff;
using Value = T; using Value = T;
using Reference = T &; using Reference = T &;
using ConstReference = const T &; using ConstReference = const T &;
using Pointer = octa::AllocatorPointer<A>; using Pointer = AllocatorPointer<A>;
using ConstPointer = octa::AllocatorConstPointer<A>; using ConstPointer = AllocatorConstPointer<A>;
using Range = octa::PointerRange<T>; using Range = PointerRange<T>;
using ConstRange = octa::PointerRange<const T>; using ConstRange = PointerRange<const T>;
using Allocator = A; using Allocator = A;
Vector(const A &a = A()): p_len(0), p_cap(0), p_buf(nullptr, a) {} Vector(const A &a = A()): p_len(0), p_cap(0), p_buf(nullptr, a) {}
explicit Vector(Size n, const T &val = T(), explicit Vector(Size n, const T &val = T(),
const A &al = A()): Vector(al) { const A &al = A()): Vector(al) {
p_buf.first() = octa::allocator_allocate(p_buf.second(), n); p_buf.first() = allocator_allocate(p_buf.second(), n);
p_len = p_cap = n; p_len = p_cap = n;
Pointer cur = p_buf.first(), last = p_buf.first() + n; Pointer cur = p_buf.first(), last = p_buf.first() + n;
while (cur != last) while (cur != last)
octa::allocator_construct(p_buf.second(), cur++, val); allocator_construct(p_buf.second(), cur++, val);
} }
Vector(const Vector &v): p_len(0), p_cap(0), p_buf(nullptr, Vector(const Vector &v): p_len(0), p_cap(0), p_buf(nullptr,
octa::allocator_container_copy(v.p_buf.second())) { allocator_container_copy(v.p_buf.second())) {
reserve(v.p_cap); reserve(v.p_cap);
p_len = v.p_len; p_len = v.p_len;
copy_contents(v); copy_contents(v);
@ -114,7 +113,7 @@ public:
} }
Vector(Vector &&v): p_len(v.p_len), p_cap(v.p_cap), p_buf(v.p_buf.first(), Vector(Vector &&v): p_len(v.p_len), p_cap(v.p_cap), p_buf(v.p_buf.first(),
octa::move(v.p_buf.second())) { move(v.p_buf.second())) {
v.p_buf.first() = nullptr; v.p_buf.first() = nullptr;
v.p_len = v.p_cap = 0; v.p_len = v.p_cap = 0;
} }
@ -123,14 +122,13 @@ public:
if (a != v.p_buf.second()) { if (a != v.p_buf.second()) {
reserve(v.p_cap); reserve(v.p_cap);
p_len = v.p_len; p_len = v.p_len;
if (octa::IsPod<T>()) { if (IsPod<T>()) {
memcpy(p_buf.first(), v.p_buf.first(), p_len * sizeof(T)); memcpy(p_buf.first(), v.p_buf.first(), p_len * sizeof(T));
} else { } else {
Pointer cur = p_buf.first(), last = p_buf.first() + p_len; Pointer cur = p_buf.first(), last = p_buf.first() + p_len;
Pointer vbuf = v.p_buf.first(); Pointer vbuf = v.p_buf.first();
while (cur != last) { while (cur != last) {
octa::allocator_construct(p_buf.second(), cur++, allocator_construct(p_buf.second(), cur++, move(*vbuf++));
octa::move(*vbuf++));
} }
} }
return; return;
@ -144,12 +142,11 @@ public:
Vector(const Value *buf, Size n, const A &a = A()): Vector(a) { Vector(const Value *buf, Size n, const A &a = A()): Vector(a) {
reserve(n); reserve(n);
if (octa::IsPod<T>()) { if (IsPod<T>()) {
memcpy(p_buf.first(), buf, n * sizeof(T)); memcpy(p_buf.first(), buf, n * sizeof(T));
} else { } else {
for (Size i = 0; i < n; ++i) for (Size i = 0; i < n; ++i)
octa::allocator_construct(p_buf.second(), allocator_construct(p_buf.second(), &p_buf.first()[i], buf[i]);
&p_buf.first()[i], buf[i]);
} }
p_len = n; p_len = n;
} }
@ -157,23 +154,23 @@ public:
Vector(InitializerList<T> v, const A &a = A()): Vector(InitializerList<T> v, const A &a = A()):
Vector(v.begin(), v.size(), a) {} Vector(v.begin(), v.size(), a) {}
template<typename R, typename = octa::EnableIf< template<typename R, typename = EnableIf<
octa::IsInputRange<R>::value && IsInputRange<R>::value &&
octa::IsConvertible<RangeReference<R>, Value>::value IsConvertible<RangeReference<R>, Value>::value
>> Vector(R range, const A &a = A()): Vector(a) { >> Vector(R range, const A &a = A()): Vector(a) {
ctor_from_range(range); ctor_from_range(range);
} }
~Vector() { ~Vector() {
clear(); clear();
octa::allocator_deallocate(p_buf.second(), p_buf.first(), p_cap); allocator_deallocate(p_buf.second(), p_buf.first(), p_cap);
} }
void clear() { void clear() {
if (p_len > 0 && !octa::IsPod<T>()) { if (p_len > 0 && !IsPod<T>()) {
Pointer cur = p_buf.first(), last = p_buf.first() + p_len; Pointer cur = p_buf.first(), last = p_buf.first() + p_len;
while (cur != last) while (cur != last)
octa::allocator_destroy(p_buf.second(), cur++); allocator_destroy(p_buf.second(), cur++);
} }
p_len = 0; p_len = 0;
} }
@ -181,9 +178,9 @@ public:
Vector &operator=(const Vector &v) { Vector &operator=(const Vector &v) {
if (this == &v) return *this; if (this == &v) return *this;
clear(); clear();
if (octa::AllocatorPropagateOnContainerCopyAssignment<A>::value) { if (AllocatorPropagateOnContainerCopyAssignment<A>::value) {
if (p_buf.second() != v.p_buf.second()) { if (p_buf.second() != v.p_buf.second()) {
octa::allocator_deallocate(p_buf.second(), p_buf.first(), p_cap); allocator_deallocate(p_buf.second(), p_buf.first(), p_cap);
p_cap = 0; p_cap = 0;
} }
p_buf.second() = v.p_buf.second(); p_buf.second() = v.p_buf.second();
@ -196,13 +193,13 @@ public:
Vector &operator=(Vector &&v) { Vector &operator=(Vector &&v) {
clear(); clear();
octa::allocator_deallocate(p_buf.second(), p_buf.first(), p_cap); allocator_deallocate(p_buf.second(), p_buf.first(), p_cap);
if (octa::AllocatorPropagateOnContainerMoveAssignment<A>::value) if (AllocatorPropagateOnContainerMoveAssignment<A>::value)
p_buf.second() = v.p_buf.second(); p_buf.second() = v.p_buf.second();
p_len = v.p_len; p_len = v.p_len;
p_cap = v.p_cap; p_cap = v.p_cap;
p_buf.~VecPair(); p_buf.~VecPair();
new (&p_buf) VecPair(v.disown(), octa::move(v.p_buf.second())); new (&p_buf) VecPair(v.disown(), move(v.p_buf.second()));
return *this; return *this;
} }
@ -210,13 +207,13 @@ public:
clear(); clear();
Size ilen = il.end() - il.begin(); Size ilen = il.end() - il.begin();
reserve(ilen); reserve(ilen);
if (octa::IsPod<T>()) { if (IsPod<T>()) {
memcpy(p_buf.first(), il.begin(), ilen); memcpy(p_buf.first(), il.begin(), ilen);
} else { } else {
Pointer tbuf = p_buf.first(), ibuf = il.begin(), Pointer tbuf = p_buf.first(), ibuf = il.begin(),
last = il.end(); last = il.end();
while (ibuf != last) { while (ibuf != last) {
octa::allocator_construct(p_buf.second(), allocator_construct(p_buf.second(),
tbuf++, *ibuf++); tbuf++, *ibuf++);
} }
} }
@ -224,9 +221,9 @@ public:
return *this; return *this;
} }
template<typename R, typename = octa::EnableIf< template<typename R, typename = EnableIf<
octa::IsInputRange<R>::value && IsInputRange<R>::value &&
octa::IsConvertible<RangeReference<R>, Value>::value IsConvertible<RangeReference<R>, Value>::value
>> Vector &operator=(R range) { >> Vector &operator=(R range) {
clear(); clear();
ctor_from_range(range); ctor_from_range(range);
@ -237,7 +234,7 @@ public:
Size l = p_len; Size l = p_len;
reserve(n); reserve(n);
p_len = n; p_len = n;
if (octa::IsPod<T>()) { if (IsPod<T>()) {
for (Size i = l; i < p_len; ++i) { for (Size i = l; i < p_len; ++i) {
p_buf.first()[i] = T(v); p_buf.first()[i] = T(v);
} }
@ -245,7 +242,7 @@ public:
Pointer first = p_buf.first() + l; Pointer first = p_buf.first() + l;
Pointer last = p_buf.first() + p_len; Pointer last = p_buf.first() + p_len;
while (first != last) while (first != last)
octa::allocator_construct(p_buf.second(), first++, v); allocator_construct(p_buf.second(), first++, v);
} }
} }
@ -253,25 +250,24 @@ public:
if (n <= p_cap) return; if (n <= p_cap) return;
Size oc = p_cap; Size oc = p_cap;
if (!oc) { if (!oc) {
p_cap = octa::max(n, Size(8)); p_cap = max(n, Size(8));
} else { } else {
while (p_cap < n) p_cap *= 2; while (p_cap < n) p_cap *= 2;
} }
Pointer tmp = octa::allocator_allocate(p_buf.second(), p_cap); Pointer tmp = allocator_allocate(p_buf.second(), p_cap);
if (oc > 0) { if (oc > 0) {
if (octa::IsPod<T>()) { if (IsPod<T>()) {
memcpy(tmp, p_buf.first(), p_len * sizeof(T)); memcpy(tmp, p_buf.first(), p_len * sizeof(T));
} else { } else {
Pointer cur = p_buf.first(), tcur = tmp, Pointer cur = p_buf.first(), tcur = tmp,
last = tmp + p_len; last = tmp + p_len;
while (tcur != last) { while (tcur != last) {
octa::allocator_construct(p_buf.second(), tcur++, allocator_construct(p_buf.second(), tcur++, move(*cur));
octa::move(*cur)); allocator_destroy(p_buf.second(), cur);
octa::allocator_destroy(p_buf.second(), cur);
++cur; ++cur;
} }
} }
octa::allocator_deallocate(p_buf.second(), p_buf.first(), oc); allocator_deallocate(p_buf.second(), p_buf.first(), oc);
} }
p_buf.first() = tmp; p_buf.first() = tmp;
} }
@ -290,36 +286,33 @@ public:
T &push(const T &v) { T &push(const T &v) {
if (p_len == p_cap) reserve(p_len + 1); if (p_len == p_cap) reserve(p_len + 1);
octa::allocator_construct(p_buf.second(), allocator_construct(p_buf.second(), &p_buf.first()[p_len], v);
&p_buf.first()[p_len], v);
return p_buf.first()[p_len++]; return p_buf.first()[p_len++];
} }
T &push(T &&v) { T &push(T &&v) {
if (p_len == p_cap) reserve(p_len + 1); if (p_len == p_cap) reserve(p_len + 1);
octa::allocator_construct(p_buf.second(), allocator_construct(p_buf.second(), &p_buf.first()[p_len], move(v));
&p_buf.first()[p_len], octa::move(v));
return p_buf.first()[p_len++]; return p_buf.first()[p_len++];
} }
T &push() { T &push() {
if (p_len == p_cap) reserve(p_len + 1); if (p_len == p_cap) reserve(p_len + 1);
octa::allocator_construct(p_buf.second(), &p_buf.first()[p_len]); allocator_construct(p_buf.second(), &p_buf.first()[p_len]);
return p_buf.first()[p_len++]; return p_buf.first()[p_len++];
} }
template<typename ...U> template<typename ...U>
T &emplace_back(U &&...args) { T &emplace_back(U &&...args) {
if (p_len == p_cap) reserve(p_len + 1); if (p_len == p_cap) reserve(p_len + 1);
octa::allocator_construct(p_buf.second(), &p_buf.first()[p_len], allocator_construct(p_buf.second(), &p_buf.first()[p_len],
octa::forward<U>(args)...); forward<U>(args)...);
return p_buf.first()[p_len++]; return p_buf.first()[p_len++];
} }
void pop() { void pop() {
if (!octa::IsPod<T>()) { if (!IsPod<T>()) {
octa::allocator_destroy(p_buf.second(), allocator_destroy(p_buf.second(), &p_buf.first()[--p_len]);
&p_buf.first()[--p_len]);
} else { } else {
--p_len; --p_len;
} }
@ -356,7 +349,7 @@ public:
Range insert(Size idx, T &&v) { Range insert(Size idx, T &&v) {
insert_base(idx, 1); insert_base(idx, 1);
p_buf.first()[idx] = octa::move(v); p_buf.first()[idx] = move(v);
return Range(&p_buf.first()[idx], &p_buf.first()[p_len]); return Range(&p_buf.first()[idx], &p_buf.first()[p_len]);
} }
@ -407,7 +400,7 @@ public:
octa::swap(p_len, v.p_len); octa::swap(p_len, v.p_len);
octa::swap(p_cap, v.p_cap); octa::swap(p_cap, v.p_cap);
octa::swap(p_buf.first(), v.p_buf.first()); octa::swap(p_buf.first(), v.p_buf.first());
if (octa::AllocatorPropagateOnContainerSwap<A>::value) if (AllocatorPropagateOnContainerSwap<A>::value)
octa::swap(p_buf.second(), v.p_buf.second()); octa::swap(p_buf.second(), v.p_buf.second());
} }