/* * 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 2015-2022 Danny Robson */ #include "concepts/named.hpp" #include #include #include namespace cruft::adapter { namespace container { /// An identity proxy for a referenced container. /// /// Provided for symmetry with `reverse` and others, so as to allow a /// common template interface. template class identity { public: identity (ContainerT &_target) : m_target (_target) { ; } decltype(auto) begin (void) & { return m_target.begin (); } decltype(auto) end (void) & { return m_target.end (); } decltype(auto) begin (void) const& { return m_target.begin (); } decltype(auto) end (void) const& { return m_target.end (); } decltype(auto) cbegin (void) const& { return m_target.cbegin (); } decltype(auto) cend (void) const& { return m_target.cend (); } private: ContainerT &m_target; }; /// Creates a reversed proxy for a referenced container. /// /// The target container must remain an l-value. /// /// It is the caller's job to ensure the targeted container remains /// valid for the duration of the proxy's lifetime. template class reverse { public: explicit reverse (T &_target): m_target (_target) { ; } auto begin (void) & { return m_target.rbegin (); } auto end (void) & { return m_target.rend (); } auto begin (void) const& { return m_target.rbegin (); } auto end (void) const& { return m_target.rend (); } auto cbegin (void) const& { return m_target.crbegin (); } auto cend (void) const& { return m_target.crend (); } private: T &m_target; }; //--------------------------------------------------------------------- template reverse (Container&) -> reverse; /////////////////////////////////////////////////////////////////////// /// Adapter's a container to return indices of the container's data /// rather than the values themselves. /// /// The targeted container must be an l-value. /// /// It is the caller's job to ensure the targeted container remains /// valid for the duration of the proxy's lifetime. template class indices { public: using typename T::size_type; explicit indices (T &_target): m_target (_target) { ; } size_type begin (void)& { return 0; } size_type end (void)& { return m_target.size (); } private: T &m_target; }; template < typename ContainerT, typename FunctionT > requires ( std::is_invocable_v< FunctionT, typename std::iterator_traits::value_type > ) class transform { public: using value_type = std::invoke_result_t< FunctionT, typename std::iterator_traits::value_type >; using pointer = void; using reference = void; using difference_type = typename std::iterator_traits< typename ContainerT::iterator >::difference_type; template transform (_ContainerT &&_container, _FunctionT &&_function) : m_container (std::forward<_ContainerT> (_container)) , m_function (std::forward< _FunctionT> (_function )) { ; } auto begin (void) const { return iterator (m_container.begin (), m_function); } auto end (void) const { return iterator (m_container.end (), m_function); } class iterator { private: using underlying = typename ContainerT::iterator; public: // HACK: We really should be using the underlying iterator's // category. However it's a massive PITA to write this code // right now. using iterator_category = std::forward_iterator_tag; //typename std::iterator_traits::iterator_category; using difference_type = typename std::iterator_traits::difference_type; using value_type = transform::value_type; using pointer = void; using reference = void; iterator ( typename ContainerT::iterator _cursor, FunctionT const &_function ) : m_cursor (_cursor) , m_function (_function) { ; } decltype(auto) operator* () { return m_function (*m_cursor); } iterator& operator++ ()& { ++m_cursor; return *this; } bool operator== (iterator const &rhs) const noexcept { return m_cursor == rhs.m_cursor; } private: typename ContainerT::iterator m_cursor; FunctionT const &m_function; }; private: ContainerT m_container; FunctionT m_function; }; template transform (ContainerT, FunctionT) -> transform< std::remove_cvref_t, std::remove_cvref_t< FunctionT> >; } namespace iterator { /////////////////////////////////////////////////////////////////////// /// Adapt's an iterator to return the n-th element of the tuple that /// corresponds to the underlying iterator::value_type when /// dereferenced. template struct scalar { public: using iterator_category = typename std::iterator_traits::iterator_category; using value_type = typename std::tuple_element< I, typename std::iterator_traits< IteratorT >::value_type >::type; using difference_type = typename std::iterator_traits::difference_type; using reference = value_type&; using const_reference = value_type const&; explicit scalar (IteratorT _inner): m_inner (_inner) { ; } const_reference operator* (void) const& { return std::get (*m_inner); } reference operator* (void)& { return std::get (*m_inner); } bool operator== (scalar rhs) { return m_inner == rhs.m_inner; } bool operator!= (scalar rhs) { return m_inner != rhs.m_inner; } scalar& operator++ (void) { ++m_inner; return *this; } private: IteratorT m_inner; }; } }