/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2010-2018 Danny Robson */ #pragma once #include "types/traits.hpp" #include "tuple/value.hpp" #include "variadic.hpp" #include "view.hpp" #include template class referencing_iterator { protected: typedef typename std::enable_if< is_dereferencable< typename Base::value_type >::value, typename Base::value_type >::type base_value_type; public: typedef typename dereferenced_type::type value_type ; typedef typename Base::difference_type difference_type ; typedef value_type& reference ; typedef value_type* pointer; typedef typename Base::iterator_category iterator_category; protected: Base m_base; public: explicit referencing_iterator (Base _base): m_base (_base) { ; } referencing_iterator& operator++() { ++m_base; return *this; } referencing_iterator operator++(int) { auto val = *this; ++m_base; return val; } bool operator== (const referencing_iterator &rhs) { return m_base == rhs.m_base; } bool operator!= (const referencing_iterator &rhs) { return m_base != rhs.m_base; } bool operator>= (const referencing_iterator &rhs) { return m_base >= rhs.m_base; } bool operator<= (const referencing_iterator &rhs) { return m_base <= rhs.m_base; } bool operator> (const referencing_iterator &rhs) { return m_base > rhs.m_base; } bool operator< (const referencing_iterator &rhs) { return m_base < rhs.m_base; } const value_type& operator*() const { return **m_base; } reference operator*() { return **m_base; } difference_type operator-(const referencing_iterator& rhs) const { return m_base - rhs.m_base; } referencing_iterator operator-(int rhs) const { return referencing_iterator (m_base - rhs); } referencing_iterator operator+(int rhs) const { return referencing_iterator (m_base + rhs); } }; namespace cruft { /////////////////////////////////////////////////////////////////////////// /// an output iterator that inserts a delimiter between successive /// assignments /// /// very useful for outputting comma seperated lists to an ostream, eg: /// /// std::copy ( /// std::cbegin (container), /// std::cend (container), /// cruft::infix_iterator (os, ", ") /// ); template < typename T, class CharT = char, class Traits = std::char_traits > class infix_iterator : public std::iterator { public: using char_type = CharT; using traits_type = Traits; using ostream_type = std::basic_ostream; infix_iterator (ostream_type& _output, const CharT *_delimiter): m_output (_output), m_delimiter (_delimiter) { ; } infix_iterator& operator= (T const &value) { if (!m_first) m_output << m_delimiter; m_output << value; m_first = false; return *this; } infix_iterator& operator* (void) { return *this; } infix_iterator& operator++ (void) { return *this; } infix_iterator& operator++ (int) { return *this; } private: bool m_first = true; ostream_type &m_output; const CharT *m_delimiter; }; namespace detail { template struct infix_t { const ContainerT &_container; const CharT *_delimiter; }; template std::ostream& operator<< (std::ostream &os, const infix_t &val) { std::copy (std::cbegin (val._container), std::cend (val._container), infix_iterator (os, val._delimiter)); return os; } }; /// a helper function that returns an object that will use a /// cruft::infix_iterator to output a container's values to an ostream with /// the given delimiter. /// /// reduces boilerplate code required to output lists of things /// /// std::cout << cruft::make_infix (container) << '\n'; template auto make_infix (const ContainerT &_container, const CharT *_delimiter = ", ") { return detail::infix_t { _container, _delimiter }; } template auto make_infix (const ValueT (&val)[CountV]) { return make_infix (cruft::view {val}); } /////////////////////////////////////////////////////////////////////////// // template struct numeric_iterator : public std::iterator< typename std::iterator_traits::iterator_category, decltype (+std::declval::value_type> ()), typename std::iterator_traits::difference_type, typename std::iterator_traits::pointer, typename std::iterator_traits::reference > { static_assert (std::is_arithmetic_v::value_type>); explicit numeric_iterator (IteratorT _inner): m_inner (_inner) { ; } auto operator++ (void) { ++m_inner; return *this; } auto operator- (const numeric_iterator &rhs) const { return typename std::iterator_traits::difference_type { m_inner - rhs.m_inner }; } auto operator* (void) const { return +*m_inner; } auto operator== (const numeric_iterator &rhs) const { return m_inner == rhs.m_inner; } auto operator!= (const numeric_iterator &rhs) const { return m_inner != rhs.m_inner; } private: IteratorT m_inner; }; //------------------------------------------------------------------------- // convenience function that constructs a view of numeric_iterators for a // provided container template auto numeric_view (ContainerT &data) { return cruft::view { numeric_iterator (std::begin (data)), numeric_iterator (std::end (data)) }; } //------------------------------------------------------------------------- template auto numeric_view (const ContainerT &data) { return cruft::view { numeric_iterator (std::begin (data)), numeric_iterator (std::end (data)) }; } /////////////////////////////////////////////////////////////////////////// template class indices { public: using value_type = std::size_t; indices (const ContainerT &_container): m_container (_container) { ; } class iterator { public: using iterator_category = std::forward_iterator_tag; iterator (value_type _index): m_index (_index) { ; } bool operator!= (const iterator &rhs) const { return m_index != rhs.m_index; } bool operator== (const iterator &rhs) const { return m_index == rhs.m_index; } iterator& operator++ (void) & { ++m_index; return *this; }; const value_type& operator* (void) const& { return m_index; } private: value_type m_index; }; iterator begin (void) const { return iterator { value_type {0} }; } iterator end (void) const { return iterator { m_container.size () }; } constexpr auto size (void) const noexcept { return std::size (m_container); } private: const ContainerT &m_container; }; template indices (ContainerT const&) -> indices; /////////////////////////////////////////////////////////////////////////// namespace detail::zip { /// A container that holds multiple iterators and returns a tuple of /// their results when dereferenced. /// /// \tparam IteratorT A tuple-like object that contains iterators template < typename IteratorT, typename = std::make_index_sequence> > struct iterator; template struct iterator> { public: // We can't declare ourselves as a forward_iterator because we're // unable to supply references to our value_type when we get // dereferenced unless we store the supplied values/references // inside ourself. // // This complicates implementation too much given we have no // pressing need for this functionality. using iterator_category = std::input_iterator_tag; using difference_type = std::ptrdiff_t; iterator (IteratorT _iterators): m_iterators (_iterators) { ; } iterator& operator++ (void) { (++std::get (m_iterators), ...); return *this; } iterator operator++ (int); auto operator* (void) { // We deliberately construct a tuple manually here to reduce // the risk of dangling references. `forward_as_tuple` and // `make_tuple` have resulted in references to locals in the // past. return std::tuple< decltype(*std::get (m_iterators))... > ( *std::get (m_iterators)... ); } bool operator== (const iterator &rhs) const { return m_iterators == rhs.m_iterators; } bool operator!= (const iterator &rhs) const { return !(*this == rhs); } private: IteratorT m_iterators; }; /// A simple container for multiple collections that returns a /// wrapped multi-iterator for begin and end. /// /// It is up to the user to ensure StoreT does not contain dangling /// references. /// /// \tparam StoreT A tuple-like object of collections (or references /// to collections). template class collection { public: collection (StoreT&&... _store): m_store (std::forward (_store)...) { ; } using indices_t = std::make_index_sequence; using begin_t = std::tuple ()))...>; using end_t = std::tuple ()))...>; auto begin (void)& { return iterator ( tuple::value::map ( [] (auto &i) noexcept { return std::begin (i); }, m_store ) ); } auto end (void)& { return iterator ( tuple::value::map ( [] (auto &i) noexcept { return std::end (i); }, m_store ) ); } private: std::tuple m_store; }; } ///------------------------------------------------------------------------ /// Takes a variable number of container arguments and returns an interable /// object with a value_type that is a tuple of the each container's /// value_type. /// /// The returned iterator value_type is suitable for using in range-for /// and structured bindings (and really, that's the entire point here). /// /// eg, cruft::zip ({1,2,3}, {4,5,6}) ~= {{1,4},{2,5},{3,6}} template auto zip (ContainerT&&... data) { CHECK (((std::size (data) == std::size (variadic::get<0> (data...))) && ...)); return detail::zip::collection ( std::forward (data)... ); } ///------------------------------------------------------------------------ /// Takes a variable number of containers and returns a zipped iterable /// object where the first of the iterator's value_types is the index of /// that iterator. ie, It combines container offsets with value_types. /// /// eg, cruft::izip ("abc") ~= {{0,'a'},{1,'b'},{2,'c'}} template auto izip (ContainerT&&... data) { indices idx (::cruft::variadic::get<0> (data...)); return zip ( std::move (idx), std::forward (data)... ); } /////////////////////////////////////////////////////////////////////////// /// an output iterator that always discards any parameters on assignment. /// /// sometimes useful to pass to algorithms that generate useful results as /// a return value, while not caring about the implicit OutputIterator /// results. struct discard_iterator : public std::iterator { template void operator= (const T&) { ; } discard_iterator& operator++ ( ) { return *this; } discard_iterator operator++ (int) { return *this; } discard_iterator& operator* ( ) { return *this; } }; /////////////////////////////////////////////////////////////////////////// /// an iterator that can be infinitely incremented but never assigned. /// /// useful for iterator ranges where the begin iterator is an output /// iterator and hence never reaches an end point (and where we don't want /// to engineer the client code to account for this). template < typename ValueT, typename CategoryT, typename DistanceT, typename PointerT, typename ReferenceT > struct unequal_iterator { using value_type = ValueT; using iterator_category = CategoryT; using difference_type = DistanceT; using pointer = PointerT; using reference = ReferenceT; unequal_iterator& operator++ ( ) { return *this; } unequal_iterator operator++ (int) { return *this; } }; //------------------------------------------------------------------------- template auto make_unequal_iterator (const ContainerT&) { using t = typename std::iterator_traits; return unequal_iterator< typename t::value_type, typename t::iterator_category, typename t::difference_type, typename t::pointer, typename t::reference > {}; }; //------------------------------------------------------------------------- template < typename OtherT, typename ValueT, typename CategoryT, typename DistanceT, typename PointerT, typename ReferenceT> constexpr bool operator== ( const unequal_iterator&, const OtherT& ) { return false; } //------------------------------------------------------------------------- template < typename OtherT, typename ValueT, typename CategoryT, typename DistanceT, typename PointerT, typename ReferenceT> constexpr bool operator== ( const OtherT&, const unequal_iterator& ) { return false; } /////////////////////////////////////////////////////////////////////////// template OutputIt _transform_by_block ( const cruft::view &, OutputIt cursor, FunctionT && ) { return cursor; } //------------------------------------------------------------------------- template OutputIt _transform_by_block ( const cruft::view &dst, OutputIt cursor, FunctionT &&func, const InputT &_src, TailT &&...tail ) { auto remain = _src; if (cursor != dst.begin ()) { auto infill = std::distance (cursor, dst.end ()); if (remain.size () < static_cast (infill)) { return _transform_by_block ( dst, std::copy_n (remain.begin (), remain.size (), cursor), std::forward (func), std::forward (tail)... ); } std::copy_n (remain.begin (), infill, cursor); func (dst); cursor = dst.begin (); remain = { remain.begin () + infill, remain.end () }; } while (remain.size () >= dst.size ()) { std::copy_n (remain.begin (), dst.size (), dst.begin ()); func (dst); remain = { remain.begin () + dst.size (), remain.end () }; } return _transform_by_block ( dst, std::copy (remain.begin (), remain.end (), cursor), std::forward (func), std::forward (tail)... ); } //------------------------------------------------------------------------- template OutputIt transform_by_block (const cruft::view &dst, FunctionT &&func, Args &&...src) { return _transform_by_block ( dst, dst.begin (), std::forward (func), std::forward (src)... ); } /////////////////////////////////////////////////////////////////////////// /// Counts the number of times the iterator is assigned to. struct counting_output_iterator { // An internal proxy value which is returned when the iterator is // dereferenced. It increments the assignment value in the host // iterator. // // The internals of this object are not a stable interface. struct assignable { assignable (std::size_t &_count) : m_count (_count) { ; } template void operator= (Arg&&) { ++m_count; } private: std::size_t &m_count; }; using value_type = assignable; using iterator_category = std::output_iterator_tag; using reference = assignable&; counting_output_iterator& operator++ () { return *this; } assignable operator* () { return assignable (m_count); } /// Returns the number of times the iterator has been assigned to. auto count (void) const { return m_count; } private: std::size_t m_count = 0; }; /////////////////////////////////////////////////////////////////////////// /// Adapts a supplied iterator by dereferencing any operations that deal /// with the underlying value_type of the supplied iterator. template struct dereference_adapter { //--------------------------------------------------------------------- using difference_type = typename std::iterator_traits::difference_type; using iterator_category = typename std::iterator_traits::iterator_category; using value_type = std::remove_reference_t< decltype( *std::declval< typename std::iterator_traits::value_type > () ) >; using pointer = value_type*; using reference = value_type&; //--------------------------------------------------------------------- dereference_adapter (IteratorT _cursor) : m_cursor (_cursor) { ; } //--------------------------------------------------------------------- // Trivial conditional operations decltype(auto) operator== (dereference_adapter const &rhs) const { return m_cursor == rhs.m_cursor; } decltype(auto) operator!= (dereference_adapter const &rhs) const { return !(*this == rhs); } //--------------------------------------------------------------------- // Iterator movement operations dereference_adapter& operator++ () { ++m_cursor; return *this; } difference_type operator- (dereference_adapter const &rhs) const { return m_cursor - rhs.m_cursor; } auto operator+ (difference_type offset) const { return dereference_adapter { m_cursor + offset }; } //--------------------------------------------------------------------- // value_type operations decltype(auto) operator= (value_type const &rhs) { return **m_cursor = rhs; } decltype(auto) operator* () { return **m_cursor; } decltype(auto) operator-> () { return **m_cursor; } decltype(auto) operator* () const { return **m_cursor; } decltype(auto) operator-> () const { return **m_cursor; } private: IteratorT m_cursor; }; }