libdpf/include/dpf/subsequence_iterable.hpp

440 lines
12 KiB
C++

/// @file dpf/subsequence_iterable.hpp
/// @author Ryan Henry <ryan.henry@ucalgary.ca>
/// @brief defines `dpf::subsequence_iterable` and associated helpers
/// @details Yields a listed subset of another iterable without copying it.
/// @copyright Copyright (c) 2019-2024 Ryan Henry and [others](@ref authors)
/// @license Released under a GNU General Public v2.0 (GPLv2) license;
/// see [LICENSE.md](@ref license) for details.
#ifndef LIBDPF_INCLUDE_DPF_SUBSEQUENCE_ITERABLE_HPP__
#define LIBDPF_INCLUDE_DPF_SUBSEQUENCE_ITERABLE_HPP__
#include <cstddef>
#include <type_traits>
#include <iterator>
#include <vector>
#include "hedley/hedley.h"
namespace dpf
{
template <typename DpfKey,
typename OutputIterT,
typename PointsIterT>
class subsequence_iterable
{
public:
using output_type = typename std::iterator_traits<OutputIterT>::value_type;
using input_type = typename DpfKey::input_type;
using output_iterator = OutputIterT;
using points_iterator = PointsIterT;
static constexpr std::size_t outputs_per_leaf = DpfKey::outputs_per_leaf;
static constexpr std::size_t lg_outputs_per_leaf = DpfKey::lg_outputs_per_leaf;
static constexpr auto mod = utils::mod_pow_2<input_type>{};
class const_iterator; // forward declaration
using iterator = const_iterator;
subsequence_iterable(output_iterator out_it, points_iterator begin, points_iterator end)
: out_it_{out_it}, begin_{begin}, end_{end}, count_{std::distance(begin_, end_)}
{ }
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
const_iterator begin() const noexcept
{
return const_iterator(out_it_, begin_);
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
const_iterator cbegin() const noexcept
{
return begin();
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
const_iterator end() const noexcept
{
return const_iterator(out_it_ + count_ * outputs_per_leaf, end_);
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
const_iterator cend() const noexcept
{
return end();
}
class const_iterator
{
public:
using value_type = output_type;
using reference = value_type;
using const_reference = reference;
using pointer = std::add_pointer_t<reference>;
using iterator_category = std::random_access_iterator_tag;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using subsequence_iterator_type = points_iterator;
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr const_iterator(output_iterator out_it, subsequence_iterator_type it) noexcept
: out_it_{out_it}, it_{it}
{ }
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr const_iterator(const_iterator &&) noexcept = default;
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr const_iterator(const const_iterator &) noexcept = default;
HEDLEY_NO_THROW
const_iterator & operator=(const_iterator &&) noexcept = default;
const_iterator & operator=(const const_iterator &) = default;
~const_iterator() = default;
HEDLEY_PURE
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr reference operator*() const noexcept
{
return out_it_[mod(*it_, lg_outputs_per_leaf)];
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr const_iterator & operator++() noexcept
{
++it_;
out_it_ += outputs_per_leaf;
return *this;
}
HEDLEY_NO_THROW
const_iterator operator++(int) noexcept
{
auto tmp = *this;
const_iterator::operator++();
return tmp;
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
const_iterator & operator--() noexcept
{
--it_;
out_it_ -= outputs_per_leaf;
return *this;
}
HEDLEY_NO_THROW
const_iterator operator--(int) noexcept
{
auto tmp = *this;
const_iterator::operator--();
return tmp;
}
const_iterator & operator+=(std::size_t n) noexcept
{
it_ += n;
out_it_ += outputs_per_leaf*n;
return *this;
}
HEDLEY_NO_THROW
const_iterator operator+(std::size_t n) const noexcept
{
return const_iterator(out_it_ + outputs_per_leaf*n, it_ + n);
}
HEDLEY_NO_THROW
const_iterator & operator-=(std::size_t n) noexcept
{
it_ -= n;
out_it_ -= outputs_per_leaf*n;
return *this;
}
HEDLEY_NO_THROW
const_iterator operator-(std::size_t n) const noexcept
{
return const_iterator(out_it_ - outputs_per_leaf*n, it_ - n);
}
HEDLEY_NO_THROW
difference_type operator-(const_iterator rhs) const noexcept
{
return it_ - rhs.it_;
}
HEDLEY_NO_THROW
reference operator[](std::size_t i) const noexcept
{
return out_it_[i*outputs_per_leaf + mod(it_[i], lg_outputs_per_leaf)];
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr bool operator==(const const_iterator & rhs) const noexcept
{
return out_it_ == rhs.out_it_ && it_ == rhs.it_;
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr bool operator<(const const_iterator & rhs) const noexcept
{
return out_it_ < rhs.out_it_ && it_ < rhs.it_;
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr bool operator!=(const const_iterator & rhs) const noexcept
{
return !(*this == rhs);
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr bool operator>(const const_iterator & rhs) const noexcept
{
return rhs < *this;
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr bool operator<=(const const_iterator & rhs) const noexcept
{
return !(rhs < *this);
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr bool operator>=(const const_iterator & rhs) const noexcept
{
return !(*this < rhs);
}
private:
output_iterator out_it_;
subsequence_iterator_type it_;
}; // class dpf::subsequence_iterable::const_iterator
private:
const output_iterator out_it_;
const points_iterator begin_;
const points_iterator end_;
const typename std::iterator_traits<points_iterator>::difference_type count_;
}; // class dpf::subsequence_iterable
template <typename IteratorT>
class recipe_subsequence_iterable
{
public:
using output_type = typename std::iterator_traits<IteratorT>::value_type;
using output_iterator = IteratorT;
class const_iterator; // forward declaration
using iterator = const_iterator;
recipe_subsequence_iterable(output_iterator out_it, const std::vector<std::size_t> & indices)
: out_it_{out_it}, indices_{indices}
{
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
const_iterator begin() const noexcept
{
return const_iterator(out_it_, std::begin(indices_));
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
const_iterator cbegin() const noexcept
{
return begin();
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
const_iterator end() const noexcept
{
return const_iterator(out_it_, std::end(indices_));
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
const_iterator cend() const noexcept
{
return end();
}
class const_iterator
{
public:
using value_type = output_type;
using reference = value_type;
using const_reference = reference;
using pointer = std::add_pointer_t<reference>;
using iterator_category = std::random_access_iterator_tag;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using subsequence_iterator_type = typename std::vector<std::size_t>::const_iterator;
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr const_iterator(output_iterator out_it, subsequence_iterator_type it) noexcept
: out_it_{out_it}, it_{it}
{ }
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr const_iterator(const_iterator &&) noexcept = default;
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr const_iterator(const const_iterator &) noexcept = default;
const_iterator & operator=(const const_iterator &) = default;
HEDLEY_NO_THROW
const_iterator & operator=(const_iterator &&) noexcept = default;
~const_iterator() = default;
HEDLEY_PURE
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr reference operator*() const noexcept
{
return out_it_[*it_];
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr const_iterator & operator++() noexcept
{
++it_;
return *this;
}
HEDLEY_NO_THROW
const_iterator operator++(int) noexcept
{
auto tmp = *this;
const_iterator::operator++();
return tmp;
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
const_iterator & operator--() noexcept
{
--it_;
return *this;
}
HEDLEY_NO_THROW
const_iterator operator--(int) noexcept
{
auto tmp = *this;
const_iterator::operator--();
return tmp;
}
const_iterator & operator+=(std::size_t n) noexcept
{
it_ += n;
return *this;
}
HEDLEY_NO_THROW
const_iterator operator+(std::size_t n) const noexcept
{
return const_iterator(out_it_, it_ + n);
}
HEDLEY_NO_THROW
const_iterator & operator-=(std::size_t n) noexcept
{
it_ -= n;
return *this;
}
HEDLEY_NO_THROW
const_iterator operator-(std::size_t n) const noexcept
{
return const_iterator(out_it_, it_ - n);
}
HEDLEY_NO_THROW
difference_type operator-(const_iterator rhs) const noexcept
{
return it_ - rhs.it_;
}
HEDLEY_NO_THROW
reference operator[](std::size_t i) const noexcept
{
return out_it_[it_[i]];
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr bool operator==(const const_iterator & rhs) const noexcept
{
return it_ == rhs.it_;
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr bool operator<(const const_iterator & rhs) const noexcept
{
return it_ < rhs.it_;
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr bool operator!=(const const_iterator & rhs) const noexcept
{
return !(*this == rhs);
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr bool operator>(const const_iterator & rhs) const noexcept
{
return rhs < *this;
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr bool operator<=(const const_iterator & rhs) const noexcept
{
return !(rhs < *this);
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr bool operator>=(const const_iterator & rhs) const noexcept
{
return !(*this < rhs);
}
private:
output_iterator out_it_;
subsequence_iterator_type it_;
}; // class dpf::recipe_subsequence_iterable::const_iterator
private:
const output_iterator out_it_;
const std::vector<std::size_t> & indices_;
}; // class dpf::recipe_subsequence_iterable
} // namespace dpf
#endif // LIBDPF_INCLUDE_DPF_SUBSEQUENCE_ITERABLE_HPP__