From 8a81eaad94dcbc90c0a6beeb0011edbf9c76b91c Mon Sep 17 00:00:00 2001 From: Suyash Mahar Date: Wed, 24 Jan 2024 10:46:30 -0800 Subject: [PATCH] Add useful iterators --- include/nvsl/iterator.hh | 236 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 include/nvsl/iterator.hh diff --git a/include/nvsl/iterator.hh b/include/nvsl/iterator.hh new file mode 100644 index 0000000..57fcfa0 --- /dev/null +++ b/include/nvsl/iterator.hh @@ -0,0 +1,236 @@ +// -*- mode: c++; c-basic-offset: 2; -*- + +/** + * @file iterator.hh + * @date janvier 24, 2024 + * @brief Implements indices operation + * + * @license Licensed under the Apache License, Version 2.0 (the "License"); from + * https://github.com/klmr/cpp11-range/ + */ + +#pragma once + +#include +#include +#include + +namespace nvsl { + + namespace detail { + + template + struct range_iter_base : std::iterator { + range_iter_base(T current) : current(current) {} + + T operator*() const { return current; } + + T const *operator->() const { return ¤t; } + + range_iter_base &operator++() { + ++current; + return *this; + } + + range_iter_base operator++(int) { + auto copy = *this; + ++*this; + return copy; + } + + bool operator==(range_iter_base const &other) const { + return current == other.current; + } + + bool operator!=(range_iter_base const &other) const { + return not(*this == other); + } + + protected: + T current; + }; + + } // namespace detail + + template + struct step_range_proxy { + struct iterator : detail::range_iter_base { + iterator(T current, T step) + : detail::range_iter_base(current), step_(step) {} + + using detail::range_iter_base::current; + + iterator &operator++() { + current += step_; + return *this; + } + + iterator operator++(int) { + auto copy = *this; + ++*this; + return copy; + } + + // Loses commutativity. Iterator-based ranges are simply broken. :-( + bool operator==(iterator const &other) const { + return step_ > 0 ? current >= other.current : current < other.current; + } + + bool operator!=(iterator const &other) const { + return not(*this == other); + } + + T step_; + }; + + step_range_proxy(T begin, T end, T step) + : begin_(begin, step), end_(end, step) {} + + iterator begin() const { return begin_; } + + iterator end() const { return end_; } + + std::size_t size() const { + if (*end_ >= *begin_) { + // Increasing and empty range + if (begin_.step_ < T{0}) return 0; + } else { + // Decreasing range + if (begin_.step_ > T{0}) return 0; + } + return std::ceil( + std::abs(static_cast(*end_ - *begin_) / begin_.step_)); + } + + private: + iterator begin_; + iterator end_; + }; + + template + struct range_proxy { + struct iterator : detail::range_iter_base { + iterator(T current) : detail::range_iter_base(current) {} + }; + + range_proxy(T begin, T end) : begin_(begin), end_(end) {} + + step_range_proxy step(T step) { return {*begin_, *end_, step}; } + + iterator begin() const { return begin_; } + + iterator end() const { return end_; } + + std::size_t size() const { return *end_ - *begin_; } + + private: + iterator begin_; + iterator end_; + }; + + template + struct step_inf_range_proxy { + struct iterator : detail::range_iter_base { + iterator(T current = T(), T step = T()) + : detail::range_iter_base(current), step(step) {} + + using detail::range_iter_base::current; + + iterator &operator++() { + current += step; + return *this; + } + + iterator operator++(int) { + auto copy = *this; + ++*this; + return copy; + } + + bool operator==(iterator const &) const { return false; } + + bool operator!=(iterator const &) const { return true; } + + private: + T step; + }; + + step_inf_range_proxy(T begin, T step) : begin_(begin, step) {} + + iterator begin() const { return begin_; } + + iterator end() const { return iterator(); } + + private: + iterator begin_; + }; + + template + struct infinite_range_proxy { + struct iterator : detail::range_iter_base { + iterator(T current = T()) : detail::range_iter_base(current) {} + + bool operator==(iterator const &) const { return false; } + + bool operator!=(iterator const &) const { return true; } + }; + + infinite_range_proxy(T begin) : begin_(begin) {} + + step_inf_range_proxy step(T step) { return {*begin_, step}; } + + iterator begin() const { return begin_; } + + iterator end() const { return iterator(); } + + private: + iterator begin_; + }; + + template + auto range(T begin, U end) + -> range_proxy::type> { + using C = typename std::common_type::type; + return {static_cast(begin), static_cast(end)}; + } + + template + infinite_range_proxy range(T begin) { + return {begin}; + } + + namespace traits { + + template + struct has_size { + template + static auto check(T *) -> typename std::is_integral< + decltype(std::declval().size())>::type; + + template + static auto check(...) -> std::false_type; + + using type = decltype(check(0)); + static constexpr bool value = type::value; + }; + + } // namespace traits + + template ::value>> + auto indices(C const &cont) -> range_proxy { + return {0, cont.size()}; + } + + template + range_proxy indices(T (&)[N]) { + return {0, N}; + } + + template + range_proxy::size_type> + indices(std::initializer_list &&cont) { + return {0, cont.size()}; + } + +} // namespace nvsl