2015-10-19 12:06:23 +11:00
|
|
|
/*
|
2018-08-04 15:14:06 +10:00
|
|
|
* 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/.
|
2015-10-19 12:06:23 +11:00
|
|
|
*
|
2022-06-23 10:58:17 +10:00
|
|
|
* Copyright 2015-2022 Danny Robson <danny@nerdcruft.net>
|
2015-10-19 12:06:23 +11:00
|
|
|
*/
|
|
|
|
|
2022-06-23 10:58:17 +10:00
|
|
|
#include "concepts/named.hpp"
|
|
|
|
|
2016-02-25 13:17:14 +11:00
|
|
|
#include <cstddef>
|
2015-10-19 12:06:23 +11:00
|
|
|
#include <iterator>
|
2020-07-01 17:02:44 +10:00
|
|
|
#include <tuple>
|
2015-10-19 12:06:23 +11:00
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
namespace cruft::adapter {
|
2015-10-19 12:06:23 +11:00
|
|
|
namespace container {
|
2019-08-06 14:31:48 +10:00
|
|
|
/// An identity proxy for a referenced container.
|
|
|
|
///
|
|
|
|
/// Provided for symmetry with `reverse` and others, so as to allow a
|
|
|
|
/// common template interface.
|
|
|
|
template <typename ContainerT>
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-12-26 15:10:21 +11:00
|
|
|
/// 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.
|
2015-10-19 12:06:23 +11:00
|
|
|
template <typename T>
|
2018-12-26 15:10:21 +11:00
|
|
|
class reverse {
|
|
|
|
public:
|
2017-05-23 12:50:51 +10:00
|
|
|
explicit reverse (T &_target):
|
2015-10-19 12:06:23 +11:00
|
|
|
m_target (_target)
|
|
|
|
{ ; }
|
|
|
|
|
2017-08-21 16:50:46 +10:00
|
|
|
auto begin (void) & { return m_target.rbegin (); }
|
|
|
|
auto end (void) & { return m_target.rend (); }
|
2015-10-19 12:06:23 +11:00
|
|
|
|
2017-08-21 16:50:46 +10:00
|
|
|
auto begin (void) const& { return m_target.rbegin (); }
|
|
|
|
auto end (void) const& { return m_target.rend (); }
|
2015-10-19 12:06:23 +11:00
|
|
|
|
2017-08-21 16:50:46 +10:00
|
|
|
auto cbegin (void) const& { return m_target.crbegin (); }
|
|
|
|
auto cend (void) const& { return m_target.crend (); }
|
2015-10-19 12:06:23 +11:00
|
|
|
|
|
|
|
private:
|
|
|
|
T &m_target;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-12-26 15:10:21 +11:00
|
|
|
//---------------------------------------------------------------------
|
2017-08-21 16:51:03 +10:00
|
|
|
template <typename Container>
|
2018-12-26 15:10:21 +11:00
|
|
|
reverse (Container&) -> reverse<Container>;
|
2017-08-21 16:51:03 +10:00
|
|
|
|
|
|
|
|
2018-12-26 15:10:21 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
/// 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.
|
2015-10-19 12:06:23 +11:00
|
|
|
template <typename T>
|
2018-12-26 15:10:21 +11:00
|
|
|
class indices {
|
|
|
|
public:
|
2015-10-19 12:06:23 +11:00
|
|
|
using typename T::size_type;
|
|
|
|
|
2017-05-23 12:50:51 +10:00
|
|
|
explicit indices (T &_target):
|
2015-10-19 12:06:23 +11:00
|
|
|
m_target (_target)
|
|
|
|
{ ; }
|
|
|
|
|
2018-12-26 15:10:21 +11:00
|
|
|
size_type begin (void)& { return 0; }
|
|
|
|
size_type end (void)& { return m_target.size (); }
|
2015-10-19 12:06:23 +11:00
|
|
|
|
|
|
|
private:
|
2018-12-26 15:10:21 +11:00
|
|
|
T &m_target;
|
2015-10-19 12:06:23 +11:00
|
|
|
};
|
2022-06-23 10:58:17 +10:00
|
|
|
|
|
|
|
|
|
|
|
template <
|
|
|
|
typename ContainerT,
|
|
|
|
typename FunctionT
|
|
|
|
>
|
|
|
|
requires (
|
|
|
|
std::is_invocable_v<
|
|
|
|
FunctionT,
|
|
|
|
typename std::iterator_traits<typename ContainerT::iterator>::value_type
|
|
|
|
>
|
|
|
|
)
|
|
|
|
class transform {
|
|
|
|
public:
|
|
|
|
using value_type = std::invoke_result_t<
|
|
|
|
FunctionT,
|
|
|
|
typename std::iterator_traits<typename ContainerT::iterator>::value_type
|
|
|
|
>;
|
|
|
|
using pointer = void;
|
|
|
|
using reference = void;
|
|
|
|
|
|
|
|
using difference_type = typename std::iterator_traits<
|
|
|
|
typename ContainerT::iterator
|
|
|
|
>::difference_type;
|
|
|
|
|
|
|
|
|
|
|
|
template <typename _ContainerT, typename _FunctionT>
|
|
|
|
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<underlying>::iterator_category;
|
|
|
|
using difference_type = typename std::iterator_traits<underlying>::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 <typename ContainerT, typename FunctionT>
|
|
|
|
transform (ContainerT, FunctionT) -> transform<
|
|
|
|
std::remove_cvref_t<ContainerT>,
|
|
|
|
std::remove_cvref_t< FunctionT>
|
|
|
|
>;
|
2015-10-19 12:06:23 +11:00
|
|
|
}
|
|
|
|
|
2018-12-26 15:10:21 +11:00
|
|
|
|
2015-10-19 12:06:23 +11:00
|
|
|
namespace iterator {
|
2018-12-26 15:10:21 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
/// Adapt's an iterator to return the n-th element of the tuple that
|
|
|
|
/// corresponds to the underlying iterator::value_type when
|
|
|
|
/// dereferenced.
|
|
|
|
template <size_t I, typename IteratorT>
|
2022-07-25 11:57:29 +10:00
|
|
|
struct scalar {
|
|
|
|
public:
|
|
|
|
using iterator_category = typename std::iterator_traits<IteratorT>::iterator_category;
|
|
|
|
using value_type = typename std::tuple_element<
|
2015-10-19 12:06:23 +11:00
|
|
|
I,
|
|
|
|
typename std::iterator_traits<
|
2018-12-26 15:10:21 +11:00
|
|
|
IteratorT
|
2015-10-19 12:06:23 +11:00
|
|
|
>::value_type
|
2022-07-25 11:57:29 +10:00
|
|
|
>::type;
|
|
|
|
using difference_type = typename std::iterator_traits<IteratorT>::difference_type;
|
2018-12-26 15:10:21 +11:00
|
|
|
using reference = value_type&;
|
2019-01-03 15:48:34 +11:00
|
|
|
using const_reference = value_type const&;
|
2015-10-19 12:06:23 +11:00
|
|
|
|
2018-12-26 15:10:21 +11:00
|
|
|
|
|
|
|
explicit scalar (IteratorT _inner):
|
2015-10-19 12:06:23 +11:00
|
|
|
m_inner (_inner)
|
|
|
|
{ ; }
|
|
|
|
|
2018-12-26 15:10:21 +11:00
|
|
|
|
2019-01-03 15:48:34 +11:00
|
|
|
const_reference operator* (void) const&
|
2015-10-19 12:06:23 +11:00
|
|
|
{ return std::get<I> (*m_inner); }
|
|
|
|
|
2018-12-26 15:10:21 +11:00
|
|
|
reference operator* (void)&
|
2015-10-19 12:06:23 +11:00
|
|
|
{ return std::get<I> (*m_inner); }
|
|
|
|
|
2018-12-26 15:10:21 +11:00
|
|
|
bool operator== (scalar<I,IteratorT> rhs) { return m_inner == rhs.m_inner; }
|
|
|
|
bool operator!= (scalar<I,IteratorT> rhs) { return m_inner != rhs.m_inner; }
|
2015-10-19 12:06:23 +11:00
|
|
|
|
2018-12-26 15:10:21 +11:00
|
|
|
|
|
|
|
scalar<I,IteratorT>& operator++ (void)
|
2015-10-19 12:06:23 +11:00
|
|
|
{ ++m_inner; return *this; }
|
|
|
|
|
2018-12-26 15:10:21 +11:00
|
|
|
|
2015-10-19 12:06:23 +11:00
|
|
|
private:
|
2018-12-26 15:10:21 +11:00
|
|
|
IteratorT m_inner;
|
2015-10-19 12:06:23 +11:00
|
|
|
};
|
|
|
|
}
|
2017-01-05 15:06:49 +11:00
|
|
|
}
|