libcruft-util/adapter.hpp

147 lines
4.7 KiB
C++

/*
* 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-2019 Danny Robson <danny@nerdcruft.net>
*/
#include <array>
#include <cstddef>
#include <iterator>
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 <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;
};
/// 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 <typename T>
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 <typename Container>
reverse (Container&) -> reverse<Container>;
///////////////////////////////////////////////////////////////////////
/// 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 <typename T>
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;
};
}
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 <size_t I, typename IteratorT>
struct scalar : public std::iterator<
typename std::iterator_traits<IteratorT>::iterator_category,
typename std::tuple_element<
I,
typename std::iterator_traits<
IteratorT
>::value_type
>::type,
typename std::iterator_traits<IteratorT>::difference_type
> {
public:
using inner_type = typename std::iterator_traits<IteratorT>::value_type;
using value_type = decltype (std::get<I> (std::declval<inner_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<I> (*m_inner); }
reference operator* (void)&
{ return std::get<I> (*m_inner); }
bool operator== (scalar<I,IteratorT> rhs) { return m_inner == rhs.m_inner; }
bool operator!= (scalar<I,IteratorT> rhs) { return m_inner != rhs.m_inner; }
scalar<I,IteratorT>& operator++ (void)
{ ++m_inner; return *this; }
private:
IteratorT m_inner;
};
}
}