enumerate.h 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. #pragma once
  2. #if __cplusplus >= 202302L
  3. #include <ranges>
  4. #if __cpp_lib_ranges_enumerate >= 202302L
  5. #define JVALIDATE_USE_STD_RANGES_ENUMERATE
  6. #endif
  7. #endif
  8. #ifdef JVALIDATE_USE_STD_RANGES_ENUMERATE
  9. namespace jvalidate::detail {
  10. using std::ranges::views::enumerate;
  11. }
  12. #else
  13. #include <iterator>
  14. #include <utility>
  15. #include <jvalidate/detail/deref_proxy.h>
  16. namespace jvalidate::detail {
  17. /**
  18. * @brief A replacement for std::ranges::views::enumerate in C++20 (as enumerate
  19. * is a C++23 feature).
  20. * Much like python's enumerate() function, this is an iterator adapter that
  21. * attaches the "index" of the iteration to each element - incrementing it as
  22. * we go.
  23. */
  24. template <typename It> class enumurate_iterator {
  25. public:
  26. using traits_t = std::iterator_traits<It>;
  27. using value_type = std::pair<size_t, typename traits_t::value_type>;
  28. using reference = std::pair<size_t const &, typename traits_t::reference>;
  29. using pointer = DerefProxy<reference>;
  30. using difference_type = typename traits_t::difference_type;
  31. using iterator_category = std::forward_iterator_tag;
  32. private:
  33. size_t index_ = 0;
  34. It iter_;
  35. public:
  36. enumurate_iterator(It iter) : iter_(iter) {}
  37. reference operator*() const { return {index_, *iter_}; }
  38. pointer operator->() const { return operator*(); }
  39. enumurate_iterator & operator++() {
  40. ++index_;
  41. ++iter_;
  42. return *this;
  43. }
  44. friend bool operator==(enumurate_iterator<It> rhs, enumurate_iterator<It> lhs) {
  45. return rhs.iter_ == lhs.iter_;
  46. }
  47. friend bool operator!=(enumurate_iterator<It> rhs, enumurate_iterator<It> lhs) {
  48. return rhs.iter_ != lhs.iter_;
  49. }
  50. };
  51. template <typename C> auto enumerate(C && container) {
  52. struct {
  53. auto begin() const { return enumurate_iterator(c.begin()); }
  54. auto end() const { return enumurate_iterator(c.end()); }
  55. C c;
  56. } rval{std::forward<C>(container)};
  57. return rval;
  58. }
  59. }
  60. #endif