toctave

t(iny)octave
git clone https://0xff.ir/g/toctave.git
Log | Files | Refs | README

commit 3ed539e164b4d88fb9599411cd085e6fcac61081
Author: Mohammad-Reza Nabipoor <mnabipoor@gnu.org>
Date:   Sat, 28 May 2022 00:49:05 +0430

stlab/: Add stlab

Diffstat:
Astlab/algorithm/reverse.hpp | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astlab/copy_on_write.hpp | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astlab/enum_ops.hpp | 367+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astlab/forest.hpp | 1229+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astlab/forest_algorithms.hpp | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astlab/functional.hpp | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astlab/iterator/set_next.hpp | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astlab/memory.hpp | 41+++++++++++++++++++++++++++++++++++++++++
Astlab/scope.hpp | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astlab/utility.hpp | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astlab/version.hpp | 31+++++++++++++++++++++++++++++++
11 files changed, 2467 insertions(+), 0 deletions(-)

diff --git a/stlab/algorithm/reverse.hpp b/stlab/algorithm/reverse.hpp @@ -0,0 +1,97 @@ +/* + Copyright 2013 Adobe + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ +/*************************************************************************************************/ + +#ifndef STLAB_ALGORITHM_REVERSE_HPP +#define STLAB_ALGORITHM_REVERSE_HPP + +#include <algorithm> +#include <utility> + +#include <stlab/iterator/set_next.hpp> + +/*************************************************************************************************/ + +namespace stlab { + +/*************************************************************************************************/ + +namespace unsafe { + +/*************************************************************************************************/ + +template <typename I> // I models NodeIterator +I reverse_append(I first, I last, I result) { + while (first != last) { + I prior(first); + ++first; + stlab::unsafe::set_next(prior, result); + result = prior; + } + return result; +} + +template <typename R, // R models NodeRange + typename I> // I models NodeIterator +inline I reverse_append(R& range, I result) { + return stlab::unsafe::reverse_append(std::begin(range), std::end(range), result); +} + +template <typename I> // I models NodeIterator +inline I reverse_nodes(I first, I last) { + return stlab::unsafe::reverse_append(first, last, last); +} + +template <typename R> // R models NodeRange +inline typename R::iterator reverse_nodes(R& range) { + return stlab::unsafe::reverse_nodes(std::begin(range), std::end(range)); +} + +/*************************************************************************************************/ + +} // namspace unsafe + +/*************************************************************************************************/ + +template <class BidirectionalRange> +inline void reverse(BidirectionalRange& range) { + std::reverse(std::begin(range), std::end(range)); +} + +template <class BidirectionalRange, class OutputIterator> +inline void reverse_copy(BidirectionalRange& range, OutputIterator result) { + std::reverse_copy(std::begin(range), std::end(range), result); +} + +template <class BidirectionalRange, class OutputIterator> +inline void reverse_copy(const BidirectionalRange& range, OutputIterator result) { + std::reverse_copy(std::begin(range), std::end(range), result); +} + +/*************************************************************************************************/ + +template <typename I> // I models BidirectionalIterator +std::pair<I, I> reverse_until(I f, I m, I l) { + while (f != m && m != l) { + --l; + + std::iter_swap(f, l); + + ++f; + } + + return std::pair<I, I>(f, l); +} + +/*************************************************************************************************/ + +} // namespace stlab + +/*************************************************************************************************/ + +#endif // STLAB_ALGORITHM_REVERSE_HPP + +/*************************************************************************************************/ diff --git a/stlab/copy_on_write.hpp b/stlab/copy_on_write.hpp @@ -0,0 +1,216 @@ +/* + Copyright 2013 Adobe + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ +/**************************************************************************************************/ + +#ifndef STLAB_COPY_ON_WRITE_HPP +#define STLAB_COPY_ON_WRITE_HPP + +/**************************************************************************************************/ + +#include <atomic> +#include <cassert> +#include <cstddef> +#include <utility> + +/**************************************************************************************************/ + +namespace stlab { + +/**************************************************************************************************/ + +template <typename T> // T models Regular +class copy_on_write { + struct model { + std::atomic<std::size_t> _count{1}; + + model() = default; + + template <class... Args> + explicit model(Args&&... args) : _value(std::forward<Args>(args)...) {} + + T _value; + }; + + model* _self; + + template <class U> + using disable_copy = std::enable_if_t<!std::is_same<std::decay_t<U>, copy_on_write>::value>*; + + template <typename U> + using disable_copy_assign = + std::enable_if_t<!std::is_same<std::decay_t<U>, copy_on_write>::value, copy_on_write&>; + +public: + /* [[deprecated]] */ using value_type = T; + + using element_type = T; + + copy_on_write() { + static model default_s; + _self = &default_s; + + // coverity[useless_call] + ++_self->_count; + } + + template <class U> + copy_on_write(U&& x, disable_copy<U> = nullptr) : _self(new model(std::forward<U>(x))) {} + + template <class U, class V, class... Args> + copy_on_write(U&& x, V&& y, Args&&... args) + : _self(new model(std::forward<U>(x), std::forward<V>(y), std::forward<Args>(args)...)) {} + + copy_on_write(const copy_on_write& x) noexcept : _self(x._self) { + assert(_self && "FATAL (sparent) : using a moved copy_on_write object"); + + // coverity[useless_call] + ++_self->_count; + } + copy_on_write(copy_on_write&& x) noexcept : _self(x._self) { + assert(_self && "WARNING (sparent) : using a moved copy_on_write object"); + x._self = nullptr; + } + + ~copy_on_write() { + if (_self && (--_self->_count == 0)) delete _self; + } + + auto operator=(const copy_on_write& x) noexcept -> copy_on_write& { + return *this = copy_on_write(x); + } + + auto operator=(copy_on_write&& x) noexcept -> copy_on_write& { + auto tmp = std::move(x); + swap(*this, tmp); + return *this; + } + + template <class U> + auto operator=(U&& x) -> disable_copy_assign<U> { + if (_self && unique()) { + _self->_value = std::forward<U>(x); + return *this; + } + + return *this = copy_on_write(std::forward<U>(x)); + } + + auto write() -> element_type& { + if (!unique()) *this = copy_on_write(read()); + + return _self->_value; + } + + auto read() const noexcept -> const element_type& { + assert(_self && "FATAL (sparent) : using a moved copy_on_write object"); + + return _self->_value; + } + + operator const element_type&() const noexcept { return read(); } + + auto operator*() const noexcept -> const element_type& { return read(); } + + auto operator-> () const noexcept -> const element_type* { return &read(); } + + bool unique() const noexcept { + assert(_self && "FATAL (sparent) : using a moved copy_on_write object"); + + return _self->_count == 1; + } + [[deprecated]] bool unique_instance() const noexcept { return unique(); } + + bool identity(const copy_on_write& x) const noexcept { + assert((_self && x._self) && "FATAL (sparent) : using a moved copy_on_write object"); + + return _self == x._self; + } + + friend inline void swap(copy_on_write& x, copy_on_write& y) noexcept { + std::swap(x._self, y._self); + } + + friend inline bool operator<(const copy_on_write& x, const copy_on_write& y) noexcept { + return !x.identity(y) && (*x < *y); + } + + friend inline bool operator<(const copy_on_write& x, const element_type& y) noexcept { + return *x < y; + } + + friend inline bool operator<(const element_type& x, const copy_on_write& y) noexcept { + return x < *y; + } + + friend inline bool operator>(const copy_on_write& x, const copy_on_write& y) noexcept { + return y < x; + } + + friend inline bool operator>(const copy_on_write& x, const element_type& y) noexcept { + return y < x; + } + + friend inline bool operator>(const element_type& x, const copy_on_write& y) noexcept { + return y < x; + } + + friend inline bool operator<=(const copy_on_write& x, const copy_on_write& y) noexcept { + return !(y < x); + } + + friend inline bool operator<=(const copy_on_write& x, const element_type& y) noexcept { + return !(y < x); + } + + friend inline bool operator<=(const element_type& x, const copy_on_write& y) noexcept { + return !(y < x); + } + + friend inline bool operator>=(const copy_on_write& x, const copy_on_write& y) noexcept { + return !(x < y); + } + + friend inline bool operator>=(const copy_on_write& x, const element_type& y) noexcept { + return !(x < y); + } + + friend inline bool operator>=(const element_type& x, const copy_on_write& y) noexcept { + return !(x < y); + } + + friend inline bool operator==(const copy_on_write& x, const copy_on_write& y) noexcept { + return x.identity(y) || (*x == *y); + } + + friend inline bool operator==(const copy_on_write& x, const element_type& y) noexcept { + return *x == y; + } + + friend inline bool operator==(const element_type& x, const copy_on_write& y) noexcept { + return x == *y; + } + + friend inline bool operator!=(const copy_on_write& x, const copy_on_write& y) noexcept { + return !(x == y); + } + + friend inline bool operator!=(const copy_on_write& x, const element_type& y) noexcept { + return !(x == y); + } + + friend inline bool operator!=(const element_type& x, const copy_on_write& y) noexcept { + return !(x == y); + } +}; +/**************************************************************************************************/ + +} // namespace stlab + +/**************************************************************************************************/ + +#endif + +/**************************************************************************************************/ diff --git a/stlab/enum_ops.hpp b/stlab/enum_ops.hpp @@ -0,0 +1,367 @@ +/* + Copyright 2013 Adobe + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ +/**************************************************************************************************/ + +#ifndef STLAB_ENUM_OPS_HPP +#define STLAB_ENUM_OPS_HPP + +/**************************************************************************************************/ + +#include <type_traits> + +/**************************************************************************************************/ + +/*! + \defgroup enum_ops Typesafe Integers and Bit Fields (enums) + \ingroup utility + + \section Description Description + + \c enum_ops provides optional typesafe bitset and arithmetic operations for enumeration types. + Without these typesafe operations, the compiler will promote the operand(s) to the appropriate + integral type, and the result will be an integral type. When the typesafe operations have been + defined for an enumeration type, \c E, the result will be of type \c E exactly when the + operand(s) are of type \c E. + + \c auto stlab_enable_bitmask_enum(E) -> std::true_type; + enables the bitset operations <code>~, |, &, ^, |=, &=, ^= </code> + for enumeration type \c E. + + \c auto stlab_enable_arithmetic_enum(E) -> std::true_type; + enables the typesafe arithmetic operations <code>+, -, *, /, + %, +=, *=, -=, /=, \%=</code> for enumeration type \c E. + + \section Definition Definition + + Defined in \link enum_ops.hpp <code>stlab/enum_ops.hpp</code> \endlink + + \section Example Example + + The following is an example of code that will compile: + \dontinclude enum_ops_example.cpp + \skip start_of_example + \until end_of_example + + The following is contains an example of code that will not compile + since the typesafe operators have not been defined. + + \dontinclude enum_ops_example_fail.cpp + \skip start_of_example + \until end_of_example +*/ + +/**************************************************************************************************/ + +namespace stlab { + +/**************************************************************************************************/ + +auto stlab_enable_bitmask_enum(...) -> std::false_type; +auto stlab_enable_arithmetic_enum(...) -> std::false_type; + +/**************************************************************************************************/ + +namespace implementation { + +/**************************************************************************************************/ + +template <class T> +using has_enabled_bitmask_t = decltype(stlab_enable_bitmask_enum(std::declval<T>())); + +template <class T> +constexpr bool has_enabled_bitmask = has_enabled_bitmask_t<T>::value; + +template <class T> +using has_enabled_arithmetic_t = decltype(stlab_enable_arithmetic_enum(std::declval<T>())); + +template <class T> +constexpr bool has_enabled_arithmetic = has_enabled_arithmetic_t<T>::value; + +template <class T, class U> +using enable_if_bitmask_or_arithmetic = + std::enable_if_t<std::disjunction_v<stlab::implementation::has_enabled_bitmask_t<T>, + stlab::implementation::has_enabled_arithmetic_t<T>>, + U>; + +template <class, bool> +struct safe_underlying_type; + +template <class T> +struct safe_underlying_type<T, true> { + using type = std::underlying_type_t<T>; +}; + +template <class T> +struct safe_underlying_type<T, false> { + using type = void; +}; + +template <class T> +using safe_underlying_type_t = typename safe_underlying_type<T, std::is_enum<T>::value>::type; + +template <class U, class T> +using is_convertible_to_underlying = + std::is_convertible<U, stlab::implementation::safe_underlying_type_t<T>>; + +/**************************************************************************************************/ + +} // namespace implementation + +/**************************************************************************************************/ + +} // namespace stlab + +/**************************************************************************************************/ + +template <class T> +constexpr auto operator&(T lhs, T rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> { + using underlying = std::underlying_type_t<T>; + return static_cast<T>(static_cast<underlying>(lhs) & static_cast<underlying>(rhs)); +} + +template <class T> +constexpr auto operator~(T a) + -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> { + using underlying = std::underlying_type_t<T>; + return static_cast<T>(~static_cast<underlying>(a)); +} + +template <class T> +constexpr auto operator|(T lhs, T rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> { + using underlying = std::underlying_type_t<T>; + return static_cast<T>(static_cast<underlying>(lhs) | static_cast<underlying>(rhs)); +} + +template <class T> +constexpr auto operator^(T lhs, T rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> { + using underlying = std::underlying_type_t<T>; + return static_cast<T>(static_cast<underlying>(lhs) ^ static_cast<underlying>(rhs)); +} + +template <class T> +constexpr auto operator<<(T lhs, std::size_t rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> { + using underlying = std::make_unsigned<std::underlying_type_t<T>>; + + return lhs = static_cast<underlying>(lhs) << static_cast<underlying>(rhs); +} + +template <class T> +constexpr auto operator>>(T lhs, std::size_t rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> { + using underlying = std::make_unsigned<std::underlying_type_t<T>>; + + return lhs = static_cast<underlying>(lhs) >> static_cast<underlying>(rhs); +} + +template <class T> +constexpr auto operator^=(T& lhs, T rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> { + return lhs = lhs ^ rhs; +} + +template <class T> +constexpr auto operator&=(T& lhs, T rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> { + return lhs = lhs & rhs; +} + +template <class T> +constexpr auto operator|=(T& lhs, T rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> { + return lhs = lhs | rhs; +} + +template <class T> +constexpr auto operator<<=(T& lhs, std::size_t rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> { + return lhs = lhs << rhs; +} + +template <class T> +constexpr auto operator>>=(T& lhs, std::size_t rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> { + return lhs = lhs >> rhs; +} + +template <class T, class U> +constexpr auto operator-(T lhs, U rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T> && + stlab::implementation::is_convertible_to_underlying<U, T>::value, + T> { + using underlying = std::underlying_type_t<T>; + return static_cast<T>(static_cast<underlying>(lhs) - static_cast<underlying>(rhs)); +} + +/**************************************************************************************************/ + +template <class T> +constexpr auto operator+(T a) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> { + using underlying = std::underlying_type_t<T>; + return static_cast<T>(+static_cast<underlying>(a)); +} + +template <class T> +constexpr auto operator-(T a) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> { + using underlying = std::underlying_type_t<T>; + return static_cast<T>(-static_cast<underlying>(a)); +} + +template <class T> +constexpr auto operator+(T lhs, T rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> { + using underlying = std::underlying_type_t<T>; + return static_cast<T>(static_cast<underlying>(lhs) + static_cast<underlying>(rhs)); +} + +template <class T> +constexpr auto operator-(T lhs, T rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> { + using underlying = std::underlying_type_t<T>; + return static_cast<T>(static_cast<underlying>(lhs) - static_cast<underlying>(rhs)); +} + +template <class T, class U> +constexpr auto operator*(T lhs, U rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> && + stlab::implementation::is_convertible_to_underlying<U, T>::value, + T> { + using underlying = std::underlying_type_t<T>; + return static_cast<T>(static_cast<underlying>(lhs) * rhs); +} + +template <class U, class T> +constexpr auto operator*(U lhs, T rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> && + stlab::implementation::is_convertible_to_underlying<U, T>::value, + T> { + using underlying = std::underlying_type_t<T>; + return static_cast<T>(lhs * static_cast<underlying>(rhs)); +} + +template <class T, class U> +constexpr auto operator/(T lhs, U rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> && + stlab::implementation::is_convertible_to_underlying<U, T>::value, + T> { + using underlying = std::underlying_type_t<T>; + return static_cast<T>(static_cast<underlying>(lhs) / rhs); +} + +template <class T, class U> +constexpr auto operator%(T lhs, U rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> && + stlab::implementation::is_convertible_to_underlying<U, T>::value, + T> { + using underlying = std::underlying_type_t<T>; + return static_cast<T>(static_cast<underlying>(lhs) % rhs); +} + +template <class T> +constexpr auto operator+=(T& lhs, T rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T&> { + return lhs = lhs + rhs; +} + +template <class T> +constexpr auto operator-=(T& lhs, T rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T&> { + return lhs = lhs - rhs; +} + +template <class T, class U> +constexpr auto operator*=(T& lhs, U rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> && + stlab::implementation::is_convertible_to_underlying<U, T>::value, + T&> { + return lhs = lhs * rhs; +} + +template <class T, class U> +constexpr auto operator/=(T& lhs, U rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> && + stlab::implementation::is_convertible_to_underlying<U, T>::value, + T&> { + return lhs = lhs / rhs; +} + +template <class T, class U> +constexpr auto operator%=(T& lhs, U rhs) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> && + stlab::implementation::is_convertible_to_underlying<U, T>::value, + T&> { + return lhs = lhs % rhs; +} + +template <class T> +constexpr auto operator++(T& lhs) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T&> { + return lhs += static_cast<T>(1); +} + +template <class T> +constexpr auto operator++(T& lhs, int) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> { + T result = lhs; + lhs += static_cast<T>(1); + return result; +} + +template <class T> +constexpr auto operator--(T& lhs) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T&> { + return lhs -= static_cast<T>(1); +} + +template <class T> +constexpr auto operator--(T& lhs, int) + -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> { + T result = lhs; + lhs -= static_cast<T>(1); + return result; +} + +/**************************************************************************************************/ + +template <class T> +constexpr auto operator==(T lhs, std::nullptr_t) + -> stlab::implementation::enable_if_bitmask_or_arithmetic<T, bool> { + return !lhs; +} + +template <class T> +constexpr auto operator==(std::nullptr_t, T rhs) + -> stlab::implementation::enable_if_bitmask_or_arithmetic<T, bool> { + return !rhs; +} + +template <class T> +constexpr auto operator!=(T lhs, std::nullptr_t rhs) + -> stlab::implementation::enable_if_bitmask_or_arithmetic<T, bool> { + return !(lhs == rhs); +} + +template <class T> +constexpr auto operator!=(std::nullptr_t lhs, T rhs) + -> stlab::implementation::enable_if_bitmask_or_arithmetic<T, bool> { + return !(lhs == rhs); +} + +template <class T> +constexpr auto operator!(T lhs) -> stlab::implementation::enable_if_bitmask_or_arithmetic<T, bool> { + return !static_cast<bool>(lhs); +} + +/**************************************************************************************************/ + +#endif + +/**************************************************************************************************/ diff --git a/stlab/forest.hpp b/stlab/forest.hpp @@ -0,0 +1,1229 @@ +/* + Copyright 2013 Adobe + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ +/**************************************************************************************************/ + +#ifndef STLAB_FOREST_HPP +#define STLAB_FOREST_HPP + +/**************************************************************************************************/ + +#include <cassert> +#include <cstddef> +#include <functional> +#include <iterator> + +#include <stlab/algorithm/reverse.hpp> +#include <stlab/iterator/set_next.hpp> + +/**************************************************************************************************/ + +namespace stlab { + +/**************************************************************************************************/ + +enum class forest_edge : bool { trailing, leading }; + +constexpr auto forest_trailing_edge{forest_edge::trailing}; +constexpr auto forest_leading_edge{forest_edge::leading}; + +/**************************************************************************************************/ + +constexpr auto pivot(forest_edge e) { return forest_edge(static_cast<bool>(e) ^ 1); } + +template <class I> // I models FullorderIterator +void pivot(I& i) { + i.edge() = pivot(i.edge()); +} + +template <class I> // I models FullorderIterator +auto pivot_of(I i) { + pivot(i); + return i; +} + +/**************************************************************************************************/ + +template <class I> // I models a FullorderIterator +auto leading_of(I i) { + i.edge() = forest_edge::leading; + return i; +} + +template <class I> // I models a FullorderIterator +auto trailing_of(I i) { + i.edge() = forest_edge::trailing; + return i; +} + +/**************************************************************************************************/ + +constexpr auto is_leading(forest_edge e) { + return e == forest_edge::leading; +} + +template <class I> // I models a FullorderIterator +auto is_leading(const I& i) { + return is_leading(i.edge()); +} + +constexpr auto is_trailing(forest_edge e) { + return e == forest_edge::trailing; +} + +template <class I> // I models a FullorderIterator +auto is_trailing(const I& i) { + return is_trailing(i.edge()); +} + +/**************************************************************************************************/ + +template <class I> // I models FullorderIterator +I find_parent(I i) { + do { + i = std::next(trailing_of(i)); + } while (i.edge() != forest_edge::trailing); + return i; +} + +/**************************************************************************************************/ + +template <class I> // I models FullorderIterator +bool has_children(const I& i) { + return !i.equal_node(std::next(leading_of(i))); +} + +/**************************************************************************************************/ + +template <class I> // I models FullorderIterator +struct child_iterator { + using value_type = typename std::iterator_traits<I>::value_type; + using difference_type = typename std::iterator_traits<I>::difference_type; + using reference = typename std::iterator_traits<I>::reference; + using pointer = typename std::iterator_traits<I>::pointer; + using iterator_category = typename std::iterator_traits<I>::iterator_category; + + child_iterator() = default; + explicit child_iterator(I x) : _x(std::move(x)) {} + template <class U> + child_iterator(const child_iterator<U>& u) : _x(u.base()) {} + + I base() const { return _x; } + + reference operator*() { return dereference(); } + pointer operator->() { return &dereference(); } + auto& operator++() { + increment(); + return *this; + } + auto operator++(int) { + auto result{*this}; + increment(); + return result; + } + auto& operator--() { + decrement(); + return *this; + } + auto operator--(int) { + auto result{*this}; + decrement(); + return result; + } + + friend bool operator==(const child_iterator& a, const child_iterator& b) { + return a.base() == b.base(); + } + friend bool operator!=(const child_iterator& a, const child_iterator& b) { return !(a == b); } + +private: + I _x; + + void increment() { + pivot(_x); + ++_x; + } + void decrement() { + --_x; + pivot(_x); + } + + reference dereference() { return *_x; } +}; + +/**************************************************************************************************/ + +template <class I> // I models FullorderIterator +I find_edge(I x, forest_edge edge) { + while (x.edge() != edge) + ++x; + return x; +} + +template <class I> // I models FullorderIterator +I find_edge_reverse(I x, forest_edge edge) { + while (x.edge() != edge) + --x; + return x; +} + +/**************************************************************************************************/ + +template <class I, forest_edge Edge> // I models FullorderIterator +struct edge_iterator { + using value_type = typename std::iterator_traits<I>::value_type; + using difference_type = typename std::iterator_traits<I>::difference_type; + using reference = typename std::iterator_traits<I>::reference; + using pointer = typename std::iterator_traits<I>::pointer; + using iterator_category = typename std::iterator_traits<I>::iterator_category; + + edge_iterator() = default; + explicit edge_iterator(I x) : _x(find_edge(x, Edge)) {} + template <class U> + edge_iterator(const edge_iterator<U, Edge>& u) : _x(u.base()) {} + + I base() const { return _x; } + + reference operator*() { return dereference(); } + pointer operator->() { return &dereference(); } + auto& operator++() { + increment(); + return *this; + } + auto operator++(int) { + auto result{*this}; + increment(); + return result; + } + auto& operator--() { + decrement(); + return *this; + } + auto operator--(int) { + auto result{*this}; + decrement(); + return result; + } + + friend bool operator==(const edge_iterator& a, const edge_iterator& b) { + return a.base() == b.base(); + } + friend bool operator!=(const edge_iterator& a, const edge_iterator& b) { return !(a == b); } + +private: + I _x; + + void increment() { _x = find_edge(std::next(_x), Edge); } + + void decrement() { _x = find_edge_reverse(std::prev(_x), Edge); } + + reference dereference() { return *_x; } +}; + +/**************************************************************************************************/ + +template <class I, // I models a Forest + class P> // P models UnaryPredicate of value_type(I) +struct filter_fullorder_iterator { + using value_type = typename std::iterator_traits<I>::value_type; + using difference_type = typename std::iterator_traits<I>::difference_type; + using reference = typename std::iterator_traits<I>::reference; + using pointer = typename std::iterator_traits<I>::pointer; + using iterator_category = typename std::iterator_traits<I>::iterator_category; + + filter_fullorder_iterator() = default; + + filter_fullorder_iterator(I f, I l, P p) : + _x(skip_forward(f, l, p)), _inside(true), _first(f), _last(l), _predicate(p) {} + + filter_fullorder_iterator(I f, I l) : + _x(skip_forward(f, l, P())), _inside(true), _first(f), _last(l) {} + + template <class U> + filter_fullorder_iterator(const filter_fullorder_iterator<U, P>& x) : + _x(x.base()), _inside(x._inside), _first(x._first), _last(x._last), + _predicate(x._predicate) {} + + P predicate() const { return _predicate; } + + forest_edge edge() const { return this->base().edge(); } + forest_edge& edge() { return this->base_reference().edge(); } + + bool equal_node(const filter_fullorder_iterator& y) const { + return this->base().equal_node(y.base()); + } + + I base() const { return _x; } + + reference operator*() { return dereference(); } + pointer operator->() { return &dereference(); } + auto& operator++() { + increment(); + return *this; + } + auto operator++(int) { + auto result{*this}; + increment(); + return result; + } + auto& operator--() { + decrement(); + return *this; + } + auto operator--(int) { + auto result{*this}; + decrement(); + return result; + } + + friend bool operator==(const filter_fullorder_iterator& a, const filter_fullorder_iterator& b) { + return a.base() == b.base(); + } + friend bool operator!=(const filter_fullorder_iterator& a, const filter_fullorder_iterator& b) { + return !(a == b); + } + +private: + I _x; + bool _inside; + I _first; + I _last; + P _predicate; + + void increment() { + I i = this->base(); + + if (i == _last) _inside = false; + ++i; + if (i == _first) _inside = true; + if (_inside) i = skip_forward(i, _last, _predicate); + this->base_reference() = i; + } + + static I skip_forward(I f, I l, P p) + // Precondition: l is on a leading edge + { + while ((f.edge() == forest_edge::leading) && (f != l) && !p(*f)) { + f.edge() = forest_edge::trailing; + ++f; + } + return f; + } + + static I skip_backward(I f, I l, P p) + // Precondition: f is on a trailing edge + { + while ((l.edge() == forest_edge::trailing) && (f != l) && !p(*l)) { + l.edge() = forest_edge::leading; + --l; + } + return l; + } + + void decrement() { + I i = this->base(); + + if (i == _first) _inside = false; + --i; + if (i == _last) _inside = true; + if (_inside) i = skip_backward(_first, i, _predicate); + this->base_reference() = i; + } + + reference dereference() { return *_x; } +}; + +/**************************************************************************************************/ + +template <class I> // I models a FullorderIterator +struct reverse_fullorder_iterator { + using iterator_type = I; + + using value_type = typename std::iterator_traits<I>::value_type; + using difference_type = typename std::iterator_traits<I>::difference_type; + using reference = typename std::iterator_traits<I>::reference; + using pointer = typename std::iterator_traits<I>::pointer; + using iterator_category = typename std::iterator_traits<I>::iterator_category; + + reverse_fullorder_iterator() : _edge(forest_edge::trailing) {} + explicit reverse_fullorder_iterator(I x) : _base(--x), _edge(pivot(_base.edge())) {} + template <class U> + reverse_fullorder_iterator(const reverse_fullorder_iterator<U>& x) : + _base(--x.base()), _edge(pivot(_base.edge())) {} + + iterator_type base() const { return std::next(_base); } + + forest_edge edge() const { return _edge; } + forest_edge& edge() { return _edge; } + + bool equal_node(const reverse_fullorder_iterator& y) const { return _base.equal_node(y._base); } + + reference operator*() { return dereference(); } + pointer operator->() { return &dereference(); } + auto& operator++() { + increment(); + return *this; + } + auto operator++(int) { + auto result{*this}; + increment(); + return result; + } + auto& operator--() { + decrement(); + return *this; + } + auto operator--(int) { + auto result{*this}; + decrement(); + return result; + } + + friend bool operator==(const reverse_fullorder_iterator& a, + const reverse_fullorder_iterator& b) { + return a.equal(b); + } + friend bool operator!=(const reverse_fullorder_iterator& a, + const reverse_fullorder_iterator& b) { + return !(a == b); + } + +private: + I _base; + forest_edge _edge; + + void increment() { + _base.edge() = pivot(_edge); + --_base; + _edge = pivot(_base.edge()); + } + void decrement() { + _base.edge() = pivot(_edge); + ++_base; + _edge = pivot(_base.edge()); + } + reference dereference() const { return *_base; } + + bool equal(const reverse_fullorder_iterator& y) const { + return (_base == y._base) && (_edge == y._edge); + } +}; + +/**************************************************************************************************/ + +template <class I> // I models FullorderIterator +struct depth_fullorder_iterator { + using value_type = typename std::iterator_traits<I>::value_type; + using difference_type = typename std::iterator_traits<I>::difference_type; + using reference = typename std::iterator_traits<I>::reference; + using pointer = typename std::iterator_traits<I>::pointer; + using iterator_category = typename std::iterator_traits<I>::iterator_category; + + depth_fullorder_iterator(difference_type d = 0) : _depth(d) {} + explicit depth_fullorder_iterator(I x, difference_type d = 0) : _x(x), _depth(d) {} + template <class U> + depth_fullorder_iterator(const depth_fullorder_iterator<U>& x) : + _x(x.base()), _depth(x._depth) {} + + difference_type depth() const { return _depth; } + forest_edge edge() const { return this->base().edge(); } + forest_edge& edge() { return _x.edge(); } + bool equal_node(depth_fullorder_iterator const& y) const { + return this->base().equal_node(y.base()); + } + + I base() const { return _x; } + + reference operator*() { return dereference(); } + pointer operator->() { return &dereference(); } + auto& operator++() { + increment(); + return *this; + } + auto operator++(int) { + auto result{*this}; + increment(); + return result; + } + auto& operator--() { + decrement(); + return *this; + } + auto operator--(int) { + auto result{*this}; + decrement(); + return result; + } + + friend bool operator==(const depth_fullorder_iterator& a, const depth_fullorder_iterator& b) { + return a.base() == b.base(); + } + friend bool operator!=(const depth_fullorder_iterator& a, const depth_fullorder_iterator& b) { + return !(a == b); + } + +private: + I _x; + difference_type _depth; + + void increment() { + forest_edge old_edge(edge()); + ++_x; + if (old_edge == edge()) + _depth += difference_type(static_cast<std::size_t>(old_edge) << 1) - 1; + } + + void decrement() { + forest_edge old_edge(edge()); + --_x; + if (old_edge == edge()) + _depth -= difference_type(static_cast<std::size_t>(old_edge) << 1) - 1; + } + + reference dereference() { return *_x; } +}; + +/**************************************************************************************************/ + +template <class Forest> +class child_adaptor; +template <class T> +class forest; + +/**************************************************************************************************/ + +namespace detail { + +/**************************************************************************************************/ + +template <class D> // derived class +struct node_base { + enum next_prior_t { prior_s, next_s }; + + using node_ptr = D*; + using reference = node_ptr&; + + node_ptr& link(forest_edge edge, next_prior_t link) { + return _nodes[static_cast<std::size_t>(edge)][static_cast<std::size_t>(link)]; + } + + node_ptr link(forest_edge edge, next_prior_t link) const { + return _nodes[static_cast<std::size_t>(edge)][static_cast<std::size_t>(link)]; + } + + node_ptr _nodes[2][2]; + + node_base() : + _nodes{{static_cast<node_ptr>(this), static_cast<node_ptr>(this)}, + {static_cast<node_ptr>(this), static_cast<node_ptr>(this)}} {} +}; + +template <class T> // T models Regular +struct node : public node_base<node<T>> { + using value_type = T; + + explicit node(const value_type& data) : _data(data) {} + + value_type _data; +}; + +/**************************************************************************************************/ + +template <class T> +struct forest_const_iterator; + +template <class T> // T is value_type +struct forest_iterator { + using value_type = T; + using difference_type = std::ptrdiff_t; + using reference = T&; + using pointer = T*; + using iterator_category = std::bidirectional_iterator_tag; + + forest_iterator() = default; + + forest_iterator(const forest_iterator& x) : _node(x._node), _edge(x._edge) {} + + forest_iterator& operator=(const forest_iterator&) = default; + + forest_edge edge() const { return _edge; } + forest_edge& edge() { return _edge; } + + bool equal_node(forest_iterator const& y) const { return _node == y._node; } + + reference operator*() const { return dereference(); } + pointer operator->() const { return &dereference(); } + auto& operator++() { + increment(); + return *this; + } + auto operator++(int) { + auto result{*this}; + increment(); + return result; + } + auto& operator--() { + decrement(); + return *this; + } + auto operator--(int) { + auto result{*this}; + decrement(); + return result; + } + + friend bool operator==(const forest_iterator& a, const forest_iterator& b) { + return a.equal(b); + } + friend bool operator!=(const forest_iterator& a, const forest_iterator& b) { return !(a == b); } + +private: + friend class stlab::forest<value_type>; + template <class> + friend struct forest_iterator; + template <class> + friend struct forest_const_iterator; + friend struct unsafe::set_next_fn<forest_iterator>; + + using node_t = node<T>; + + reference dereference() const { return _node->_data; } + + void increment() { + node_t* next(_node->link(_edge, node_t::next_s)); + + if (is_leading(_edge)) + _edge = forest_edge(next != _node); + else + _edge = forest_edge(next->link(forest_edge::leading, node_t::prior_s) == _node); + + _node = next; + } + + void decrement() { + node_t* next(_node->link(_edge, node_t::prior_s)); + + if (is_leading(_edge)) + _edge = forest_edge(next->link(forest_edge::trailing, node_t::next_s) != _node); + else + _edge = forest_edge(next == _node); + + _node = next; + } + + bool equal(const forest_iterator& y) const { return (_node == y._node) && (_edge == y._edge); } + + node_t* _node{nullptr}; + forest_edge _edge{forest_edge::leading}; + + forest_iterator(node_t* node, forest_edge edge) : _node(node), _edge(edge) {} +}; + +/**************************************************************************************************/ + +template <class T> // T is value_type +struct forest_const_iterator { + using value_type = const T; + using difference_type = std::ptrdiff_t; + using reference = const T&; + using pointer = const T*; + using iterator_category = std::bidirectional_iterator_tag; + + forest_const_iterator() = default; + + forest_const_iterator(const forest_const_iterator& x) : _node(x._node), _edge(x._edge) {} + + forest_const_iterator& operator=(const forest_const_iterator&) = default; + + forest_const_iterator(const forest_iterator<T>& x) : _node(x._node), _edge(x._edge) {} + + forest_edge edge() const { return _edge; } + forest_edge& edge() { return _edge; } + bool equal_node(forest_const_iterator const& y) const { return _node == y._node; } + + reference operator*() const { return dereference(); } + pointer operator->() const { return &dereference(); } + auto& operator++() { + increment(); + return *this; + } + auto operator++(int) { + auto result{*this}; + increment(); + return result; + } + auto& operator--() { + decrement(); + return *this; + } + auto operator--(int) { + auto result{*this}; + decrement(); + return result; + } + + friend bool operator==(const forest_const_iterator& a, const forest_const_iterator& b) { + return a.equal(b); + } + friend bool operator!=(const forest_const_iterator& a, const forest_const_iterator& b) { + return !(a == b); + } + +private: + template <class> + friend class stlab::forest; + template <class> + friend struct forest_const_iterator; + friend struct unsafe::set_next_fn<forest_const_iterator>; + + using node_t = const node<T>; + + reference dereference() const { return _node->_data; } + + void increment() { + node_t* next(_node->link(_edge, node_t::next_s)); + + if (is_leading(_edge)) + _edge = forest_edge(next != _node); + else + _edge = forest_edge(next->link(forest_edge::leading, node_t::prior_s) == _node); + + _node = next; + } + + void decrement() { + node_t* next(_node->link(_edge, node_t::prior_s)); + + if (is_leading(_edge)) + _edge = forest_edge(next->link(forest_edge::trailing, node_t::next_s) != _node); + else + _edge = forest_edge(next == _node); + + _node = next; + } + + bool equal(const forest_const_iterator& y) const { + return (_node == y._node) && (_edge == y._edge); + } + + node_t* _node{nullptr}; + forest_edge _edge{forest_edge::leading}; + + forest_const_iterator(node_t* node, forest_edge edge) : _node(node), _edge(edge) {} +}; + +/**************************************************************************************************/ + +} // namespace detail + +/**************************************************************************************************/ + +namespace unsafe { + +/**************************************************************************************************/ + +template <class T> // T is node<T> +struct set_next_fn<detail::forest_iterator<T>> { + void operator()(detail::forest_iterator<T> x, detail::forest_iterator<T> y) const { + using node_t = typename detail::node<T>; + + x._node->link(x.edge(), node_t::next_s) = y._node; + y._node->link(y.edge(), node_t::prior_s) = x._node; + } +}; + +/**************************************************************************************************/ + +} // namespace unsafe + +/**************************************************************************************************/ + +template <class T> +class forest { +private: + using node_t = detail::node<T>; + friend class child_adaptor<forest<T>>; + +public: + // types + using reference = T&; + using const_reference = const T&; + using iterator = detail::forest_iterator<T>; + using const_iterator = detail::forest_const_iterator<T>; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reverse_iterator = reverse_fullorder_iterator<iterator>; + using const_reverse_iterator = reverse_fullorder_iterator<const_iterator>; + + /* qualification needed since: A name N used in a class S shall refer to the same declaration + in its context and when re-evaluated in the completed scope of + S. */ + using child_iterator = stlab::child_iterator<iterator>; + using const_child_iterator = stlab::child_iterator<const_iterator>; + using reverse_child_iterator = std::reverse_iterator<child_iterator>; + + using preorder_iterator = edge_iterator<iterator, forest_edge::leading>; + using const_preorder_iterator = edge_iterator<const_iterator, forest_edge::leading>; + using postorder_iterator = edge_iterator<iterator, forest_edge::trailing>; + using const_postorder_iterator = edge_iterator<const_iterator, forest_edge::trailing>; + + forest() = default; + ~forest() { clear(); } + + forest(const forest& x) : forest() { + insert(end(), const_child_iterator(x.begin()), const_child_iterator(x.end())); + } + forest(forest&& x) noexcept : forest() { splice(end(), x); } + forest& operator=(const forest& x) { + return *this = forest(x); + } + forest& operator=(forest&& x) noexcept { + auto tmp{move(x)}; // this is `release()` + clear(); // these two lines are `reset()` + splice(end(), tmp); + return *this; + } + + void swap(forest& x) { std::swap(*this, x); } + + size_type size() const; + size_type max_size() const { return size_type(-1); } + bool size_valid() const { return _size != 0 || empty(); } + bool empty() const { return begin() == end(); } // Don't test size which may be expensive + + // iterators + iterator root() { return iterator(tail(), forest_edge::leading); } + const_iterator root() const { return const_iterator(tail(), forest_edge::leading); } + + iterator begin() { return ++root(); } + iterator end() { return iterator(tail(), forest_edge::trailing); } + const_iterator begin() const { return ++root(); } + const_iterator end() const { return const_iterator(tail(), forest_edge::trailing); } + + reverse_iterator rbegin() { return reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + + reference front() { + assert(!empty()); + return *begin(); + } + const_reference front() const { + assert(!empty()); + return *begin(); + } + reference back() { + assert(!empty()); + return *(--end()); + } + const_reference back() const { + assert(!empty()); + return *(--end()); + } + + // modifiers + void clear() { + erase(begin(), end()); + assert(empty()); // Make sure our erase is correct + } + + iterator erase(const iterator& position); + iterator erase(const iterator& first, const iterator& last); + + iterator insert(const iterator& position, T x) { + iterator result(new node_t(std::move(x)), forest_edge::leading); + + if (size_valid()) ++_size; + + unsafe::set_next(std::prev(position), result); + unsafe::set_next(std::next(result), position); + + return result; + } + + void push_front(const T& x) { insert(begin(), x); } + void push_back(const T& x) { insert(end(), x); } + void pop_front() { + assert(!empty()); + erase(begin()); + } + void pop_back() { + assert(!empty()); + erase(--end()); + } + + iterator insert(iterator position, const_child_iterator first, const_child_iterator last); + + iterator splice(iterator position, forest<T>& x); + iterator splice(iterator position, forest<T>& x, iterator i); + iterator splice(iterator position, forest<T>& x, child_iterator first, child_iterator last); + iterator splice(iterator position, + forest<T>& x, + child_iterator first, + child_iterator last, + size_type count); + + iterator insert_parent(child_iterator front, child_iterator back, const T& x); + void reverse(child_iterator first, child_iterator last); + +private: + friend struct detail::forest_iterator<value_type>; + friend struct detail::forest_const_iterator<value_type>; + friend struct unsafe::set_next_fn<iterator>; + + mutable size_type _size{0}; + detail::node_base<node_t> _tail; + + node_t* tail() { return static_cast<node_t*>(&_tail); } + const node_t* tail() const { return static_cast<const node_t*>(&_tail); } +}; + +/**************************************************************************************************/ + +template <class T> +bool operator==(const forest<T>& x, const forest<T>& y) { + if (x.size() != y.size()) return false; + + for (auto first(x.begin()), last(x.end()), pos(y.begin()); first != last; ++first, ++pos) { + if (first.edge() != pos.edge()) return false; + if (is_leading(first) && (*first != *pos)) return false; + } + + return true; +} + +template <class T> +bool operator!=(const forest<T>& x, const forest<T>& y) { + return !(x == y); +} + +/**************************************************************************************************/ + +namespace unsafe { + +/**************************************************************************************************/ + +template <class I> // I models a FullorderIterator +struct set_next_fn<child_iterator<I>> { + void operator()(child_iterator<I> x, child_iterator<I> y) { + unsafe::set_next(pivot_of(x.base()), y.base()); + } +}; + +/**************************************************************************************************/ + +} // namespace unsafe + +/**************************************************************************************************/ + +template <class T> +typename forest<T>::size_type forest<T>::size() const { + if (!size_valid()) { + const_preorder_iterator first(begin()); + const_preorder_iterator last(end()); + + _size = size_type(std::distance(first, last)); + } + + return _size; +} + +/**************************************************************************************************/ + +template <class T> +typename forest<T>::iterator forest<T>::erase(const iterator& first, const iterator& last) { + difference_type stack_depth(0); + iterator position(first); + + while (position != last) { + if (position.edge() == forest_edge::leading) { + ++stack_depth; + ++position; + } else { + if (stack_depth > 0) + position = erase(position); + else + ++position; + stack_depth = std::max<difference_type>(0, stack_depth - 1); + } + } + return last; +} + +/**************************************************************************************************/ + +template <class T> +typename forest<T>::iterator forest<T>::erase(const iterator& position) { + /* + NOTE (sparent) : After the first call to set_next() the invariants of the forest are + violated and we can't determing leading/trailing if we navigate from the affected node. + So we gather all the iterators up front then do the set_next calls. + */ + + if (size_valid()) --_size; + + iterator leading_prior(std::prev(leading_of(position))); + iterator leading_next(std::next(leading_of(position))); + iterator trailing_prior(std::prev(trailing_of(position))); + iterator trailing_next(std::next(trailing_of(position))); + + if (has_children(position)) { + unsafe::set_next(leading_prior, leading_next); + unsafe::set_next(trailing_prior, trailing_next); + } else { + unsafe::set_next(leading_prior, trailing_next); + } + + delete position._node; + + return is_leading(position) ? std::next(leading_prior) : trailing_next; +} + +/**************************************************************************************************/ + +template <class T> +typename forest<T>::iterator forest<T>::splice(iterator position, forest<T>& x) { + return splice(position, x, child_iterator(x.begin()), child_iterator(x.end()), + x.size_valid() ? x.size() : 0); +} + +/**************************************************************************************************/ + +template <class T> +typename forest<T>::iterator forest<T>::splice(iterator position, forest<T>& x, iterator i) { + i.edge() = forest_edge::leading; + return splice(position, x, child_iterator(i), ++child_iterator(i), has_children(i) ? 0 : 1); +} + +/**************************************************************************************************/ + +template <class T> +typename forest<T>::iterator forest<T>::insert(iterator pos, + const_child_iterator f, + const_child_iterator l) { + for (const_iterator first(f.base()), last(l.base()); first != last; ++first, ++pos) { + if (is_leading(first)) pos = insert(pos, *first); + } + + return pos; +} + +/**************************************************************************************************/ + +template <class T> +typename forest<T>::iterator forest<T>::splice( + iterator pos, forest<T>& x, child_iterator first, child_iterator last, size_type count) { + if (first == last || first.base() == pos) return pos; + + if (&x != this) { + if (count) { + if (size_valid()) _size += count; + if (x.size_valid()) x._size -= count; + } else { + _size = 0; + x._size = 0; + } + } + + iterator back(std::prev(last.base())); + + unsafe::set_next(std::prev(first), last); + + unsafe::set_next(std::prev(pos), first.base()); + unsafe::set_next(back, pos); + + return first.base(); +} + +/**************************************************************************************************/ + +template <class T> +typename forest<T>::iterator forest<T>::splice(iterator pos, + forest<T>& x, + child_iterator first, + child_iterator last) { + return splice(pos, x, first, last, 0); +} + +/**************************************************************************************************/ + +template <class T> +typename forest<T>::iterator forest<T>::insert_parent(child_iterator first, + child_iterator last, + const T& x) { + iterator result(insert(last.base(), x)); + if (first == last) return result; + splice(trailing_of(result), *this, first, child_iterator(result)); + return result; +} + +/**************************************************************************************************/ + +template <class T> +void forest<T>::reverse(child_iterator first, child_iterator last) { + iterator prior(first.base()); + --prior; + first = unsafe::reverse_nodes(first, last); + unsafe::set_next(prior, first.base()); +} + +/**************************************************************************************************/ + +template <class I> // I models FullorderIterator +child_iterator<I> child_begin(const I& x) { + return child_iterator<I>(std::next(leading_of(x))); +} + +/**************************************************************************************************/ + +template <class I> // I models FullorderIterator +child_iterator<I> child_end(const I& x) { + return child_iterator<I>(trailing_of(x)); +} + +/**************************************************************************************************/ + +template <class Forest> +class child_adaptor { +public: + using forest_type = Forest; + using value_type = typename Forest::value_type; + using iterator_type = typename Forest::iterator; + using reference = typename Forest::reference; + using const_reference = typename Forest::const_reference; + using difference_type = typename Forest::difference_type; + using iterator = typename Forest::child_iterator; + + child_adaptor(forest_type& f, iterator_type& i) : _forest(f), _iterator(i) {} + + value_type& back() { return *(--child_end(_iterator)); } + value_type& front() { return *(child_begin(_iterator)); } + + void push_back(const value_type& x) { _forest.insert(child_end(_iterator).base(), x); } + void push_front(const value_type& x) { _forest.insert(child_begin(_iterator).base(), x); } + + void pop_back() { _forest.erase(--child_end(_iterator).base()); } + void pop_front() { _forest.erase(child_begin(_iterator).base()); } + +private: + child_adaptor(); // not defined + + forest_type& _forest; + iterator_type& _iterator; +}; + +/**************************************************************************************************/ + +template <class I> +struct forest_range { + I _f; + I _l; + + auto begin() const { return _f; } + auto end() const { return _l; } +}; + +/**************************************************************************************************/ + +template <class I> // I models FullorderIterator +auto child_range(const I& x) { + return forest_range<child_iterator<I>>{child_begin(x), child_end(x)}; +} + +/**************************************************************************************************/ + +template <class R, typename P> // R models FullorderRange +auto filter_fullorder_range(R& x, P p) { + using iterator = filter_fullorder_iterator<typename R::iterator, P>; + + return forest_range<iterator>{iterator(std::begin(x), std::end(x), p), + iterator(std::end(x), std::end(x), p)}; +} + +template <class R, typename P> // R models FullorderRange +auto filter_fullorder_range(const R& x, P p) { + using iterator = filter_fullorder_iterator<typename R::const_iterator, P>; + + return forest_range<iterator>{iterator(std::begin(x), std::end(x), p), + iterator(std::end(x), std::end(x), p)}; +} + +/**************************************************************************************************/ + +template <class R> // R models FullorderRange +auto reverse_fullorder_range(R& x) { + using iterator = reverse_fullorder_iterator<typename R::iterator>; + + return forest_range<iterator>{iterator(std::end(x)), iterator(std::begin(x))}; +} + +template <class R> // R models FullorderRange +auto reverse_fullorder_range(const R& x) { + using iterator = reverse_fullorder_iterator<typename R::const_iterator>; + + return forest_range<iterator>{iterator(std::end(x)), iterator(std::begin(x))}; +} + +/**************************************************************************************************/ + +template <class R> // R models FullorderRange +auto depth_range(R& x) { + using iterator = depth_fullorder_iterator<typename R::iterator>; + + return forest_range<iterator>{iterator(std::begin(x)), iterator(std::end(x))}; +} + +template <class R> // R models FullorderRange +auto depth_range(const R& x) { + using iterator = depth_fullorder_iterator<typename R::const_iterator>; + + return forest_range<iterator>{iterator(std::begin(x)), iterator(std::end(x))}; +} + +/**************************************************************************************************/ + +template <class R> // R models FullorderRange +auto postorder_range(R& x) { + using iterator = edge_iterator<typename R::iterator, forest_edge::trailing>; + + return forest_range<iterator>{iterator(std::begin(x)), iterator(std::end(x))}; +} + +template <class R> // R models FullorderRange +auto postorder_range(const R& x) { + using iterator = edge_iterator<typename R::const_iterator, forest_edge::trailing>; + + return forest_range<iterator>{iterator(std::begin(x)), iterator(std::end(x))}; +} + +/**************************************************************************************************/ + +template <class R> // R models FullorderRange +auto preorder_range(R& x) { + using iterator = edge_iterator<typename R::iterator, forest_edge::leading>; + + return forest_range<iterator>{iterator(std::begin(x)), iterator(std::end(x))}; +} + +template <class R> // R models FullorderRange +auto preorder_range(const R& x) { + using iterator = edge_iterator<typename R::const_iterator, forest_edge::leading>; + + return forest_range<iterator>{iterator(std::begin(x)), iterator(std::end(x))}; +} + +/**************************************************************************************************/ + +} // namespace stlab + +/**************************************************************************************************/ + +#endif // STLAB_FOREST_HPP + +/**************************************************************************************************/ diff --git a/stlab/forest_algorithms.hpp b/stlab/forest_algorithms.hpp @@ -0,0 +1,146 @@ +/**************************************************************************************************/ + +#ifndef STLAB_FOREST_ALGORITHMS_HPP +#define STLAB_FOREST_ALGORITHMS_HPP + +/**************************************************************************************************/ + +// stlab +#include <stlab/concurrency/optional.hpp> +#include <stlab/forest.hpp> + +/**************************************************************************************************/ + +namespace stlab { + +/**************************************************************************************************/ + +namespace forests { + +/**************************************************************************************************/ +// "Congruent" would be a nice name here, but in geometry that also implies reflection. +template <class Forest1, class Forest2> +bool equal_shape(const Forest1& x, const Forest2& y) { + if (x.size_valid() && y.size_valid() && x.size() != y.size()) return false; + auto pos{y.begin()}; + for (auto first(x.begin()), last(x.end()); first != last; ++first, ++pos) { + if (first.edge() != pos.edge()) return false; + } + return true; +} + +/**************************************************************************************************/ + +template <class Container> +struct transcribe_iterator { + using iterator_category = std::output_iterator_tag; + using value_type = void; + using difference_type = void; + using pointer = void; + using reference = void; + using container_type = Container; + + transcribe_iterator(Container& c, typename Container::iterator i) : _c{&c}, _i{std::move(i)} {} + + constexpr auto& operator*() { return *this; } + constexpr auto& operator++() { + ++_i; + return *this; + } + constexpr auto operator++(int) { + auto result{*this}; + ++_i; + return result; + } + + constexpr auto& operator=(const typename Container::value_type& value) { + _i = _c->insert(_i, value); + return *this; + } + + constexpr auto& operator=(typename Container::value_type&& value) { + _i = _c->insert(_i, std::move(value)); + return *this; + } + + constexpr auto trailing() { _i = trailing_of(_i); } + +private: + Container* _c; + typename Container::iterator _i; +}; + +template <class Container> +auto transcriber(Container& c) { + return transcribe_iterator<Container>(c, c.begin()); +} + +/**************************************************************************************************/ + +template <class I, class O, class P, class UP> +auto transcribe(I first, I last, O out, P proj, UP pred) { + for (; first != last; ++first, ++out) { + if (pred(first)) { + out = proj(*first); + } else { + out.trailing(); + } + } + return out; +} + +template <class R, class O, class P, class UP> +auto transcribe(const R& range, O out, P proj, UP pred) { + return transcribe(std::cbegin(range), std::cend(range), std::move(out), std::move(proj), + std::move(pred)); +} + +template <class I, class O, class P> +auto transcribe(I first, I last, O out, P proj) { + return transcribe(std::move(first), std::move(last), std::move(out), std::move(proj), + [](const auto& p) { return is_leading(p); }); +} + +template <class R, class O, class P> +auto transcribe(const R& range, O out, P proj) { + return transcribe(std::cbegin(range), std::cend(range), std::move(out), std::move(proj)); +} + +/**************************************************************************************************/ + +template <class I, // models ForestFullorderIterator + class O> // models OutputIterator +auto flatten(I first, I last, O out) { + for (; first != last; ++first) { + if (is_leading(first)) { + *out++ = *first; + } else { + *out++ = nullopt; + } + } + return out; +} + +/**************************************************************************************************/ + +template <class I, // I models ForwardIterator; I::value_type == stlab::optional<T> + class F> // F models Forest +auto unflatten(I first, I last, F& f) { + return forests::transcribe( + first, last, transcriber(f), [](const auto& x) { return *x; }, + [](const auto& p) { return *p; }); +} + +/**************************************************************************************************/ + +} // namespace forests + +/**************************************************************************************************/ + +} // namespace stlab + +/**************************************************************************************************/ + +#endif // STLAB_FOREST_ALGORITHMS_HPP + +/**************************************************************************************************/ diff --git a/stlab/functional.hpp b/stlab/functional.hpp @@ -0,0 +1,83 @@ +/* + Copyright 2017 Adobe + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/**************************************************************************************************/ + +#ifndef STLAB_FUNCTIONAL_HPP +#define STLAB_FUNCTIONAL_HPP + +/**************************************************************************************************/ + +#include <functional> +#include <type_traits> + +/**************************************************************************************************/ + +namespace stlab { + +/**************************************************************************************************/ + +inline namespace v1 { +/**************************************************************************************************/ + +template <class T> +struct unwrap_reference { + using type = T; +}; + +template <class T> +struct unwrap_reference<std::reference_wrapper<T>> { + using type = T; +}; + +template <class T> +using unwrap_reference_t = typename unwrap_reference<T>::type; + +/**************************************************************************************************/ + +template <class T> +struct is_reference_wrapper : std::false_type {}; +template <class T> +struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; + +template <class T> +constexpr bool is_reference_wrapper_v = is_reference_wrapper<T>::value; + +/**************************************************************************************************/ + +template <typename T> +T& unwrap(T& val) { + return val; +} + +template <typename T> +const T& unwrap(const T& val) { + return val; +} + +template <typename T> +T& unwrap(std::reference_wrapper<T>& val) { + return val.get(); +} + +template <typename T> +const T& unwrap(const std::reference_wrapper<T>& val) { + return val.get(); +} + +/**************************************************************************************************/ + +} // namespace v1 + +/**************************************************************************************************/ + +} // namespace stlab + +/**************************************************************************************************/ + +#endif + +/**************************************************************************************************/ diff --git a/stlab/iterator/set_next.hpp b/stlab/iterator/set_next.hpp @@ -0,0 +1,62 @@ +/* + Copyright 2013 Adobe + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ +/*************************************************************************************************/ + +#ifndef STLAB_ITERATOR_SET_NEXT_HPP +#define STLAB_ITERATOR_SET_NEXT_HPP + +/*************************************************************************************************/ + +namespace stlab { + +/*************************************************************************************************/ + +namespace unsafe { + +/*************************************************************************************************/ + +template <typename I> // I models NodeIterator +struct set_next_fn; // Must be specialized + +/*************************************************************************************************/ + +template <typename I> // I models NodeIterator +inline void set_next(I x, I y) { + set_next_fn<I>()(x, y); +} + +/*************************************************************************************************/ + +template <typename I> // T models ForwardNodeIterator +inline void splice_node_range(I location, I first, I last) { + I successor(std::next(location)); + set_next(location, first); + set_next(last, successor); +} + +template <typename I> // I models ForwardNodeIterator +inline void skip_next_node(I location) { + set_next(location, std::next(std::next(location))); +} + +template <typename I> // I models BidirectionalNodeIterator +inline void skip_node(I location) { + set_next(std::prev(location), std::next(location)); +} + +/*************************************************************************************************/ + +} // namespace unsafe + +/*************************************************************************************************/ + +} // namespace stlab + +/*************************************************************************************************/ + +#endif // STLAB_ITERATOR_SET_NEXT_HPP + +/*************************************************************************************************/ diff --git a/stlab/memory.hpp b/stlab/memory.hpp @@ -0,0 +1,40 @@ +/* + Copyright 2017 Adobe + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/**************************************************************************************************/ + +#ifndef STLAB_MEMORY_HPP +#define STLAB_MEMORY_HPP + +/**************************************************************************************************/ + +#include <memory> + +/**************************************************************************************************/ + +namespace stlab { + +/**************************************************************************************************/ + +inline namespace v1 { +/**************************************************************************************************/ + +template <typename T> +auto make_weak_ptr(const std::shared_ptr<T>& x) { + return std::weak_ptr<T>(x); +} + +/**************************************************************************************************/ + +} // namespace v1 + +/**************************************************************************************************/ + +} // namespace stlab + +/**************************************************************************************************/ + +#endif +\ No newline at end of file diff --git a/stlab/scope.hpp b/stlab/scope.hpp @@ -0,0 +1,68 @@ +/* + Copyright 2015 Adobe + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/**************************************************************************************************/ + +#ifndef STLAB_SCOPE_HPP +#define STLAB_SCOPE_HPP + +/**************************************************************************************************/ + +#include <mutex> +#include <tuple> +#include <utility> + +/**************************************************************************************************/ + +namespace stlab { + +/**************************************************************************************************/ + +inline namespace v1 { +/**************************************************************************************************/ + +namespace detail { + +template <typename T, typename Tuple, size_t... S> +auto scope_call(Tuple&& t, std::index_sequence<S...>) { + T scoped(std::forward<std::tuple_element_t<S, Tuple>>(std::get<S>(t))...); + (void)scoped; + + // call the function + constexpr size_t last_index = std::tuple_size<Tuple>::value - 1; + return std::forward<std::tuple_element_t<last_index, Tuple>>(std::get<last_index>(t))(); +} + +} // namespace detail + +/**************************************************************************************************/ + +template <typename T, typename... Args> +inline auto scope(Args&&... args) { + return detail::scope_call<T>(std::forward_as_tuple(std::forward<Args>(args)...), + std::make_index_sequence<sizeof...(args) - 1>()); +} + +/* Workaround until VS2017 bug is fixed */ +template <typename T, typename F> +inline auto scope(std::mutex& m, F&& f) { + T scoped(m); + return std::forward<F>(f)(); +} + +/**************************************************************************************************/ + +} // namespace v1 + +/**************************************************************************************************/ + +} // namespace stlab + +/**************************************************************************************************/ + +#endif + +/**************************************************************************************************/ diff --git a/stlab/utility.hpp b/stlab/utility.hpp @@ -0,0 +1,127 @@ +/* + Copyright 2017 Adobe + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/**************************************************************************************************/ + +#ifndef STLAB_UTILITY_HPP +#define STLAB_UTILITY_HPP + +/**************************************************************************************************/ + +#include <array> +#include <type_traits> + +/**************************************************************************************************/ + +namespace stlab { + +/**************************************************************************************************/ + +inline namespace v1 { +/**************************************************************************************************/ + +namespace detail { + +/**************************************************************************************************/ + +template <bool, class T> +struct move_if_helper; + +template <class T> +struct move_if_helper<true, T> { + using type = std::remove_reference_t<T>&&; +}; + +template <class T> +struct move_if_helper<false, T> { + using type = std::remove_reference_t<T>&; +}; + +template <bool P, class T> +using move_if_helper_t = typename move_if_helper<P, T>::type; + +/**************************************************************************************************/ + +} // namespace detail + +/**************************************************************************************************/ + +template <class Seq1, class Seq2> +struct index_sequence_cat; + +template <std::size_t... N1, std::size_t... N2> +struct index_sequence_cat<std::index_sequence<N1...>, std::index_sequence<N2...>> { + using type = std::index_sequence<N1..., N2...>; +}; + +template <class Seq1, class Seq2> +using index_sequence_cat_t = typename index_sequence_cat<Seq1, Seq2>::type; + +/**************************************************************************************************/ + +template <class Seq> +struct index_sequence_to_array; + +template <std::size_t... N> +struct index_sequence_to_array<std::index_sequence<N...>> { + static constexpr std::array<std::size_t, sizeof...(N)> value{{N...}}; +}; + +/**************************************************************************************************/ + +template <class Seq, template <std::size_t> class F, std::size_t Index, std::size_t Count> +struct index_sequence_transform; + +template <class Seq, + template <std::size_t> class F, + std::size_t Index = 0, + std::size_t Count = Seq::size()> +using index_sequence_transform_t = typename index_sequence_transform<Seq, F, Index, Count>::type; + +template <class Seq, template <std::size_t> class F, std::size_t Index, std::size_t Count> +struct index_sequence_transform { + using type = index_sequence_cat_t< + index_sequence_transform_t<Seq, F, Index, Count / 2>, + index_sequence_transform_t<Seq, F, Index + Count / 2, Count - Count / 2>>; +}; + +template <class Seq, template <std::size_t> class F, std::size_t Index> +struct index_sequence_transform<Seq, F, Index, 0> { + using type = std::index_sequence<>; +}; + +template <class Seq, template <std::size_t> class F, std::size_t Index> +struct index_sequence_transform<Seq, F, Index, 1> { + using type = typename F<index_sequence_to_array<Seq>::value[Index]>::type; +}; + +/**************************************************************************************************/ + +template <bool P, class T> +constexpr detail::move_if_helper_t<P, T> move_if(T&& t) noexcept { + return static_cast<detail::move_if_helper_t<P, T>>(t); +} + +/**************************************************************************************************/ + +template <class F, class... Args> +void for_each_argument(F&& f, Args&&... args) { + return (void)std::initializer_list<int>{(std::forward<F>(f)(args), 0)...}; +} + +/**************************************************************************************************/ + +} // namespace v1 + +/**************************************************************************************************/ + +} // namespace stlab + +/**************************************************************************************************/ + +#endif + +/**************************************************************************************************/ diff --git a/stlab/version.hpp b/stlab/version.hpp @@ -0,0 +1,31 @@ +/* + Copyright 2015 Adobe + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +// See http://www.stlab.cc for documentation + +#ifndef STLAB_VERSION_HPP +#define STLAB_VERSION_HPP + +// +// Caution: this is the only stlab header that is guaranteed +// to change with every stlab release. Including this header +// will cause a recompile every time a new stlab version is +// used. +// +// STLAB_VERSION % 100 is the patch level +// STLAB_VERSION / 100 % 1000 is the minor version +// STLAB_VERSION / 100000 is the major version + +#define STLAB_VERSION 100602 + +// +// STLAB_LIB_VERSION must be defined to be the same as STLAB_VERSION +// but as a *string* in the form "x_y[_z]" where x is the major version +// number, y is the minor version number, and z is the patch level if not 0. + +#define STLAB_LIB_VERSION "1_6_2" + +#endif