2026-09-24 14:08:32 -06:00
|
|
|
/// @file grotto/offset_iterable.hpp
|
|
|
|
|
/// @author Ryan Henry <ryan.henry@ucalgary.ca>
|
2026-09-24 23:18:10 -06:00
|
|
|
/// @brief A sorted range shifted by a public offset, viewed through `rotation_iterable`.
|
|
|
|
|
/// @details The rotation starts at the first entry strictly greater than the offset.
|
2026-09-24 14:08:32 -06:00
|
|
|
/// @copyright Copyright (c) 2019-2023 Ryan Henry and others
|
|
|
|
|
/// @license Released under a GNU General Public v2.0 (GPLv2) license;
|
|
|
|
|
/// see [LICENSE.md](@ref GPLv2) for details.
|
|
|
|
|
|
|
|
|
|
#ifndef LIBDPF_INCLUDE_GROTTO_OFFSET_VIEW_HPP__
|
|
|
|
|
#define LIBDPF_INCLUDE_GROTTO_OFFSET_VIEW_HPP__
|
|
|
|
|
|
|
|
|
|
#include "hedley/hedley.h"
|
|
|
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
#include <iterator>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
|
|
|
|
#include "dpf/rotation_iterable.hpp"
|
|
|
|
|
#include "dpf/utils.hpp"
|
|
|
|
|
|
|
|
|
|
namespace grotto
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
template <typename WrappedIterator> struct offset_iterator;
|
|
|
|
|
|
|
|
|
|
template <typename WrappedIterator> struct offset_const_iterator;
|
|
|
|
|
|
|
|
|
|
template <typename WrappedIterator>
|
|
|
|
|
struct offset_iterable
|
|
|
|
|
{
|
|
|
|
|
using wrapped_iterator = WrappedIterator;
|
|
|
|
|
using iterator = offset_iterator<typename dpf::rotation_iterable<wrapped_iterator>::iterator>;
|
|
|
|
|
using const_iterator = offset_const_iterator<typename dpf::rotation_iterable<wrapped_iterator>::const_iterator>;
|
|
|
|
|
|
|
|
|
|
using value_type = typename std::iterator_traits<wrapped_iterator>::value_type;
|
|
|
|
|
using size_type = std::size_t;
|
|
|
|
|
using difference_type = typename std::iterator_traits<wrapped_iterator>::difference_type;
|
|
|
|
|
using reference = std::add_const_t<typename std::iterator_traits<wrapped_iterator>::reference>;
|
|
|
|
|
using const_reference = std::add_const_t<typename std::iterator_traits<wrapped_iterator>::reference>;
|
|
|
|
|
using pointer = typename std::iterator_traits<wrapped_iterator>::pointer;
|
|
|
|
|
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr offset_iterable(wrapped_iterator begin, wrapped_iterator end,
|
|
|
|
|
size_type offset)
|
2026-09-24 23:18:10 -06:00
|
|
|
: rotation_{begin, end, std::distance(begin,
|
2026-09-24 14:08:32 -06:00
|
|
|
std::upper_bound(begin, end, offset, std::less_equal<value_type>{}))},
|
|
|
|
|
offset_{offset}
|
|
|
|
|
{
|
|
|
|
|
assert(std::is_sorted(begin, end));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr value_type operator[](size_type index) const
|
|
|
|
|
{
|
2026-09-24 23:18:10 -06:00
|
|
|
return rotation_[index] - offset_;
|
2026-09-24 14:08:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr auto rotation() const
|
|
|
|
|
{
|
2026-09-24 23:18:10 -06:00
|
|
|
return rotation_;
|
2026-09-24 14:08:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr auto offset() const
|
|
|
|
|
{
|
|
|
|
|
return offset_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iterator begin()
|
|
|
|
|
{
|
2026-09-24 23:18:10 -06:00
|
|
|
return iterator{std::begin(rotation_), offset_};
|
2026-09-24 14:08:32 -06:00
|
|
|
}
|
|
|
|
|
const_iterator begin() const
|
|
|
|
|
{
|
2026-09-24 23:18:10 -06:00
|
|
|
return const_iterator{std::begin(rotation_), offset_};
|
2026-09-24 14:08:32 -06:00
|
|
|
}
|
|
|
|
|
constexpr const_iterator cbegin() const
|
|
|
|
|
{
|
|
|
|
|
return begin();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iterator end()
|
|
|
|
|
{
|
2026-09-24 23:18:10 -06:00
|
|
|
return iterator{std::end(rotation_), offset_};
|
2026-09-24 14:08:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const_iterator end() const
|
|
|
|
|
{
|
2026-09-24 23:18:10 -06:00
|
|
|
return const_iterator{std::end(rotation_), offset_};
|
2026-09-24 14:08:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr const_iterator cend() const
|
|
|
|
|
{
|
|
|
|
|
return end();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2026-09-24 23:18:10 -06:00
|
|
|
dpf::rotation_iterable<wrapped_iterator> rotation_;
|
2026-09-24 14:08:32 -06:00
|
|
|
size_type offset_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename WrappedIterator>
|
|
|
|
|
struct offset_iterator_base
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
using wrapped_iterator = WrappedIterator;
|
|
|
|
|
using value_type = typename std::iterator_traits<wrapped_iterator>::value_type;
|
|
|
|
|
using reference = typename std::iterator_traits<wrapped_iterator>::reference;
|
|
|
|
|
using const_reference = std::conditional_t<
|
|
|
|
|
std::is_reference_v<reference>,
|
|
|
|
|
std::add_lvalue_reference_t<std::add_const_t<std::remove_reference_t<reference>>>,
|
|
|
|
|
std::add_const_t<reference>>;
|
|
|
|
|
using size_type = std::size_t;
|
|
|
|
|
|
2026-09-24 20:44:07 -06:00
|
|
|
HEDLEY_NO_THROW
|
2026-09-24 14:08:32 -06:00
|
|
|
constexpr offset_iterator_base(wrapped_iterator iter, size_type offset) noexcept
|
|
|
|
|
: it{iter}, offset_{offset} { }
|
|
|
|
|
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr bool operator==(const offset_iterator_base & rhs) const noexcept
|
|
|
|
|
{
|
|
|
|
|
return it == rhs.it
|
|
|
|
|
&& offset_ == rhs.offset_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr bool operator!=(const offset_iterator_base & rhs) const noexcept
|
|
|
|
|
{
|
|
|
|
|
return !(*this == rhs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
wrapped_iterator it;
|
|
|
|
|
size_type offset_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename WrappedIterator>
|
|
|
|
|
struct offset_iterator : public offset_iterator_base<WrappedIterator>
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
using base = offset_iterator_base<WrappedIterator>;
|
|
|
|
|
public:
|
|
|
|
|
using base::base;
|
|
|
|
|
using typename base::value_type;
|
|
|
|
|
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr offset_iterator & operator++() noexcept
|
|
|
|
|
{
|
|
|
|
|
++this->it;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr offset_iterator operator++(int) noexcept
|
|
|
|
|
{
|
|
|
|
|
auto tmp = *this;
|
|
|
|
|
++(*this);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr offset_iterator & operator--() noexcept
|
|
|
|
|
{
|
|
|
|
|
--this->it;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr offset_iterator operator--(int) noexcept
|
|
|
|
|
{
|
|
|
|
|
auto tmp = *this;
|
|
|
|
|
--(*this);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr auto operator*() const
|
|
|
|
|
{
|
|
|
|
|
return static_cast<value_type>(*this->it) - this->offset_;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename WrappedIterator>
|
|
|
|
|
struct offset_const_iterator : public offset_iterator_base<WrappedIterator>
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
using base = offset_iterator_base<WrappedIterator>;
|
|
|
|
|
public:
|
|
|
|
|
using base::base;
|
|
|
|
|
using typename base::value_type;
|
|
|
|
|
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr offset_const_iterator & operator++() noexcept
|
|
|
|
|
{
|
|
|
|
|
++this->it;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr offset_const_iterator operator++(int) noexcept
|
|
|
|
|
{
|
|
|
|
|
auto tmp = *this;
|
|
|
|
|
++(*this);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr offset_const_iterator & operator--() noexcept
|
|
|
|
|
{
|
|
|
|
|
--this->it;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr offset_const_iterator operator--(int) noexcept
|
|
|
|
|
{
|
|
|
|
|
auto tmp = *this;
|
|
|
|
|
--(*this);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr auto operator*() const
|
|
|
|
|
{
|
|
|
|
|
return static_cast<value_type>(*this->it) - this->offset_;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename ContainerT>
|
|
|
|
|
auto offset_by(const ContainerT & container, typename ContainerT::size_type offset)
|
|
|
|
|
{
|
|
|
|
|
return offset_iterable{std::begin(container), std::end(container), offset};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// assumes the range is sorted
|
|
|
|
|
template <typename IteratorT,
|
|
|
|
|
typename InputT,
|
|
|
|
|
typename Function,
|
|
|
|
|
std::enable_if_t<std::is_same_v<InputT, typename std::iterator_traits<IteratorT>::value_type>, bool> = false>
|
|
|
|
|
constexpr auto for_each_offset(IteratorT begin, IteratorT end, InputT offset, Function && f)
|
|
|
|
|
{
|
|
|
|
|
assert(std::is_sorted(begin, end));
|
|
|
|
|
|
|
|
|
|
InputT val = -offset;
|
|
|
|
|
dpf::utils::flip_msb_if_signed_integral(val);
|
|
|
|
|
|
|
|
|
|
auto size = std::distance(begin, end);
|
|
|
|
|
// find the new "start" of the sorted sequence after offsetting by offset
|
|
|
|
|
std::size_t new_first = std::distance(begin,
|
|
|
|
|
std::upper_bound(begin, end, val, std::less_equal<void>{}));
|
|
|
|
|
|
|
|
|
|
// iterate in sorted order. `new_first` is the index of the
|
|
|
|
|
// lexicographically smallest value in the `[begin,end)` after
|
|
|
|
|
// shifting each element by `-offset`
|
|
|
|
|
// in the input such that `*next(begin, new_first)
|
|
|
|
|
auto it = std::next(begin, new_first);
|
|
|
|
|
for (std::size_t i = new_first; i < size; ++i, ++it) f(i, *it - val);
|
|
|
|
|
it = begin;
|
|
|
|
|
for (std::size_t i = 0; i < new_first; ++i, ++it) f(i, *it - val);
|
|
|
|
|
return new_first;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace grotto
|
|
|
|
|
|
|
|
|
|
#endif // LIBDPF_INCLUDE_GROTTO_OFFSET_VIEW_HPP__
|