kblib  0.2.3
General utilities library for modern C++
iterators.h
Go to the documentation of this file.
1 /* *****************************************************************************
2  * kblib is a general utility library for C++14 and C++17, intended to provide
3  * performant high-level abstractions and more expressive ways to do simple
4  * things.
5  *
6  * Copyright (c) 2021 killerbee
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  * ****************************************************************************/
21 
32 #ifndef KBLIB_ITERATORS_H
33 #define KBLIB_ITERATORS_H
34 
35 #include "enumerate-contrib-cry.h"
36 #include "enumerate-contrib-tw.h"
37 #include "fakestd.h"
38 
39 #include <cassert>
40 #include <iterator>
41 #include <vector>
42 
43 #if KBLIB_USE_CXX17
44 # include <optional>
45 #endif
46 
47 namespace kblib {
48 
49 template <typename ptr>
51  constexpr auto operator()(ptr&& p) const noexcept -> auto {
52  return to_pointer_impl<decltype(p.operator->())>{}(p.operator->());
53  }
54  constexpr auto operator()(const ptr& p) const noexcept -> auto {
55  return to_pointer_impl<decltype(p.operator->())>{}(p.operator->());
56  }
57 };
58 
59 template <typename T>
60 struct to_pointer_impl<T*> {
61  constexpr auto operator()(T* p) const noexcept -> T* { return p; }
62 };
63 
70 template <typename P>
71 constexpr auto to_pointer(P&& p) noexcept -> auto* {
73 }
74 
75 template <typename Container,
76  typename Comp = std::less<value_type_linear_t<Container>>>
77 auto max_element(Container& c, Comp comp) -> value_type_linear_t<Container>* {
78  auto it = max_element(std::begin(c), std::end(c), comp);
79  if (it != std::end(c)) {
80  return to_pointer(it);
81  } else {
82  return nullptr;
83  }
84 }
89 template <typename T, typename E, typename = void>
90 struct is_output_iterator_for : std::false_type {};
91 
92 template <typename T, typename E>
94  T, E, void_t<decltype(*std::declval<T&>()++ = std::declval<const E&>())>>
95  : std::true_type {};
96 
97 template <typename Container>
107  public:
108  using value_type = void;
109  using difference_type = std::ptrdiff_t;
110  using pointer = void;
111  using reference = void;
112  using iterator_category = std::output_iterator_tag;
113 
114  counting_back_insert_iterator() noexcept = default;
115  explicit counting_back_insert_iterator(Container& c, std::size_t n = 0)
116  : container(std::addressof(c))
117  , count(n) {}
118  explicit counting_back_insert_iterator(std::size_t n)
119  : count(n) {}
120 
121  struct proxy_iterator {
122  using value_type = typename Container::value_type;
123 
124  auto operator=(const value_type& value) & -> proxy_iterator& {
125  assert(container);
126  // Multiple assignments for a single dereference are not allowed
127  assert(*dirty);
128  *dirty = false;
129  container->push_back(value);
130  return *this;
131  }
132 
133  auto operator=(value_type&& value) & -> proxy_iterator& {
134  assert(container);
135  // Multiple assignments for a single dereference are not allowed
136  assert(*dirty);
137  *dirty = false;
138  container->push_back(std::move(value));
139  return *this;
140  }
141 
142  Container* container;
143  bool* dirty;
144  };
145 
146  auto operator*() noexcept -> proxy_iterator {
147  assert(dirty);
148  return {container, &dirty};
149  }
150 
152  assert(not dirty);
153  ++count;
154  dirty = true;
155  return *this;
156  }
157  auto operator++(int) noexcept -> counting_back_insert_iterator = delete;
158 
160  const counting_back_insert_iterator& b) noexcept
161  -> bool {
162  return a.count == b.count;
163  }
165  const counting_back_insert_iterator& b) noexcept
166  -> bool {
167  return a.count != b.count;
168  }
170  const counting_back_insert_iterator& b) noexcept
171  -> bool {
172  return a.count < b.count;
173  }
175  const counting_back_insert_iterator& b) noexcept
176  -> bool {
177  return a.count <= b.count;
178  }
180  const counting_back_insert_iterator& b) noexcept
181  -> bool {
182  return a.count > b.count;
183  }
185  const counting_back_insert_iterator& b) noexcept
186  -> bool {
187  return a.count >= b.count;
188  }
190  const counting_back_insert_iterator& b) noexcept
191  -> std::ptrdiff_t {
192  return std::ptrdiff_t(a.count) - ptrdiff_t(b.count);
193  }
194 
195  protected:
196  Container* container = nullptr;
197  std::size_t count = 0;
198  bool dirty = true;
199 };
200 
201 template <typename C>
203  C& c, std::size_t count = 0) {
204  return counting_back_insert_iterator<C>{c, count};
205 }
206 
220 template <typename Value, typename Delta>
221 class range_t {
222  private:
223  Value min, max;
224  Delta step;
225 
226  constexpr static bool nothrow_copyable
227  = std::is_nothrow_copy_constructible<Value>::value;
228  constexpr static bool nothrow_steppable = noexcept(min + step);
229 
230  public:
239  constexpr range_t(Value min_, Value max_, Delta step_ = 1)
240  : min(min_)
241  , max(max_)
242  , step(step_) {
243  normalize();
244  }
251  constexpr range_t(Value max_)
252  : range_t(Value{}, max_, (max_ >= Value{}) ? 1 : -1) {}
253 
258  struct iterator {
259  Value val;
260  Delta step;
261 
262  using difference_type = std::ptrdiff_t;
263  using value_type = Value;
264  using pointer = const Value*;
265  using reference = Value;
266  using iterator_category = std::input_iterator_tag;
267 
273  constexpr auto operator*() const noexcept(nothrow_copyable) -> Value {
274  return val;
275  }
282  constexpr auto operator->() const noexcept -> pointer { return &val; }
288  constexpr auto operator++() & noexcept(nothrow_steppable) -> iterator& {
289  val = static_cast<Value>(val + step);
290  return *this;
291  }
298  constexpr auto operator++(int) noexcept(nothrow_steppable) -> iterator {
299  auto ret = *this;
300  val = val + step;
301  return ret;
302  }
309  constexpr friend auto operator==(iterator l, iterator r) noexcept
310  -> bool {
311  return l.val == r.val and l.step == r.step;
312  }
319  constexpr friend auto operator!=(iterator l, iterator r) noexcept
320  -> bool {
321  return l.val != r.val or l.step != r.step;
322  }
329  constexpr friend auto operator<(iterator l, iterator r) noexcept -> bool {
330  if (l.step > 0)
331  return l.val < r.val;
332  else
333  return l.val > r.val;
334  }
341  constexpr friend auto operator<=(iterator l, iterator r) noexcept
342  -> bool {
343  return not (r < l);
344  }
351  constexpr friend auto operator>(iterator l, iterator r) noexcept -> bool {
352  return r < l;
353  }
360  constexpr friend auto operator>=(iterator l, iterator r) noexcept
361  -> bool {
362  return not (l < r);
363  }
364  constexpr auto operator[](std::ptrdiff_t x) const noexcept -> Value {
365  return static_cast<Value>(val + x * step);
366  }
367  template <typename Integral>
368  constexpr auto operator[](Integral x) const noexcept -> Value {
369  return static_cast<Value>(val + std::ptrdiff_t(x) * step);
370  }
371  };
372 
376  constexpr auto begin() const noexcept -> iterator { return {min, step}; }
380  constexpr auto end() const noexcept -> iterator { return {max, step}; }
381 
385  constexpr auto size() const noexcept -> std::size_t {
386  return static_cast<std::size_t>(std::abs(max - min) / step);
387  }
388 
392  friend constexpr auto begin(const range_t& r) noexcept -> iterator {
393  return {r.min, r.step};
394  }
398  friend constexpr auto end(const range_t& r) noexcept -> iterator {
399  return {r.max, r.step};
400  }
401 
405  friend constexpr auto size(const range_t& r) noexcept -> std::size_t {
406  return (r.max - r.min) / r.step;
407  }
408 
412  constexpr auto empty() const noexcept -> bool { return size() == 0; }
413 
414  template <typename Integral>
415  constexpr auto operator[](Integral x) const noexcept
416  -> decltype(begin()[x]) {
417  return begin()[x];
418  }
419 
420  constexpr auto lesser() const noexcept(nothrow_copyable) -> Value {
421  return (step > 0) ? max : min;
422  }
423 
424  constexpr auto greater() const noexcept(nothrow_copyable) -> Value {
425  return (step > 0) ? min : max;
426  }
427 
431  template <
432  typename Container,
433  enable_if_t<
434  is_linear_container_v<
435  Container> and std::is_constructible<Container, iterator, iterator>::value>* = nullptr>
436  explicit operator Container() const
437  noexcept(noexcept(Container(std::declval<iterator>(),
438  std::declval<iterator>()))) {
439  return Container(begin(), end());
440  }
441 
445  template <
446  typename Container,
447  enable_if_t<
448  is_setlike_v<
449  Container> and std::is_constructible<Container, iterator, iterator>::value>* = nullptr>
450  explicit operator Container() const
451  noexcept(noexcept(Container(std::declval<iterator>(),
452  std::declval<iterator>()))) {
453  return Container(begin(), end());
454  }
455 
461  constexpr friend auto operator==(range_t l, range_t r) noexcept -> bool {
462  return (l.empty() and r.empty())
463  or ((l.begin() == r.begin()) and (l.end() == r.end())
464  and (l.step == r.step));
465  }
471  constexpr friend auto operator!=(range_t l, range_t r) noexcept -> bool {
472  return not (l == r);
473  }
474 
475  private:
476  template <typename T>
477  static constexpr enable_if_t<not std::is_signed<T>::value, std::true_type>
478  positive(const T&) {
479  return {};
480  }
481  template <typename T>
482  static constexpr enable_if_t<std::is_signed<T>::value, bool> positive(T v) {
483  return v >= 0;
484  }
485  template <typename R, typename T,
486  enable_if_t<std::is_integral<R>::value
487  and std::is_integral<T>::value>* = nullptr>
488  static constexpr auto signed_cast(T v) {
489  return kblib::signed_cast<R>(v);
490  }
491  template <typename R, typename T,
492  enable_if_t<not (std::is_integral<R>::value
493  and std::is_integral<T>::value)>* = nullptr>
494  static constexpr auto signed_cast(T v) {
495  return v;
496  }
497 
498  constexpr auto normalize() noexcept(nothrow_steppable) -> void {
499  if (min == max) {
500  } else if (step == 0) {
501  if (min != std::numeric_limits<Value>::max()) {
502  max = min + 1;
503  } else {
504  max = min - 1;
505  }
506  } else {
507 #pragma GCC diagnostic push
508 #pragma GCC diagnostic ignored "-Wsign-conversion"
509 #pragma GCC diagnostic ignored "-Wconversion"
510 #pragma GCC diagnostic ignored "-Wsign-compare"
511 #pragma GCC diagnostic ignored "-Wimplicit-int-conversion"
512 #pragma GCC diagnostic ignored "-Wshorten-64-to-32"
513  auto difference = max - min;
514  std::ptrdiff_t sign = (step > 0) ? 1 : -1;
515  if ((sign * to_signed(difference)) <= (sign * step)) {
516  step = sign;
517  max = min + step;
518  } else {
519  auto remainder = difference % step;
520  if (remainder != 0) {
521  max = max - remainder;
522  assert(not (positive(max)
523  and (signed_cast<Delta>(
525  < step)));
526  max = max + step;
527  }
528  }
529 #pragma GCC diagnostic pop
530  }
531  }
532 };
533 
534 namespace detail_iterators {
535  template <typename T, typename U, typename = void>
536  struct is_addable : std::false_type {};
537 
538  template <typename T, typename U>
539  struct is_addable<T, U,
540  void_t<decltype(std::declval<T&>() + std::declval<U&>())>>
541  : std::true_type {};
542 } // namespace detail_iterators
543 
544 struct adjuster {
545  std::ptrdiff_t adj;
546  constexpr adjuster(std::ptrdiff_t adj_) noexcept
547  : adj(adj_) {}
548  constexpr operator std::ptrdiff_t() const noexcept { return adj; }
549 };
550 
551 template <typename T>
552 constexpr auto operator+(T val, adjuster a) noexcept
554  decltype(std::advance(val, a.adj))> {
555  return std::advance(val, a.adj);
556 }
557 
562 struct incrementer {
563  constexpr incrementer() noexcept = default;
564  constexpr incrementer(int) noexcept {}
565  constexpr operator int() const noexcept { return 1; }
566  friend constexpr auto operator*(std::ptrdiff_t x, incrementer) {
567  return adjuster{x};
568  }
569 
570  template <typename T>
571  constexpr auto operator()(T& t) -> T& {
572  return ++t;
573  }
574 };
575 
579 template <typename T>
580 constexpr auto operator+(T val, incrementer) -> T {
581  return ++val;
582 }
583 
588 struct decrementer {
589  constexpr decrementer() noexcept = default;
590  constexpr decrementer(int) noexcept {}
591  constexpr operator int() const noexcept { return -1; }
592  friend constexpr auto operator*(std::ptrdiff_t x, decrementer) {
593  return adjuster{-x};
594  }
595  template <typename T>
596  constexpr auto operator()(T& t) -> T& {
597  return --t;
598  }
599 };
600 
604 template <typename T>
605 constexpr auto operator+(T val, decrementer) -> T {
606  return --val;
607 }
608 
619 template <typename Value, typename Delta = int>
620 constexpr auto range(Value min, Value max, Delta step = 0)
622  if (step == 0) {
623  if (min <= max) {
624  return {min, max, 1};
625  } else {
626  return {min, max, -1};
627  }
628  } else {
629  return {min, max, step};
630  }
631 }
632 
640 template <typename Value>
641 constexpr auto range(Value max) -> range_t<Value, incrementer> {
642  return {max};
643 }
644 
645 #if KBLIB_USE_CXX17
646 
647 template <typename Value, typename Delta>
648 class irange_t {
649  public:
650  Value min, max;
651  Delta step;
652 
653  constexpr static bool nothrow_copyable
654  = std::is_nothrow_copy_constructible<Value>::value;
655  constexpr static bool nothrow_steppable = noexcept(min + step);
656 };
657 
658 template <typename Value, typename Delta = int>
659 constexpr auto irange(Value, Value, Delta = 0) {}
660 
661 template <typename T>
662 class enumerator_iterator;
663 
667 namespace detail_enumerate {
668 
669  template <typename T1, typename T2>
670  auto get_or(T1&& t1, T2&& t2) -> decltype(auto) {
671  return t1 ? *t1 : *t2;
672  }
673 
674  struct force_copy_tag {};
675  // Get a pointer which is guaranteed to be invalid to use (but not UB to
676  // merely store)
677  template <typename T>
678  auto get_magic_ptr() -> T* {
679  static const char enumeration_magic_pointer = '\0';
680  return reinterpret_cast<T*>(
681  const_cast<char*>(&enumeration_magic_pointer));
682  }
683 
684 } // namespace detail_enumerate
685 
686 template <typename T>
687 class enumeration {
688  public:
689  enumeration() = default;
690 
691  enumeration(const enumeration& other)
692  : idx(other.idx)
693  , local([&] {
694  assert(other.source or other.local);
695  assert(other.source != detail_enumerate::get_magic_ptr<T>());
696  return other.copied();
697  }())
698  , source(nullptr) {}
699  enumeration(volatile enumeration& other)
700  : enumeration(const_cast<const enumeration&>(other)) {}
701 
703  auto operator=(const enumeration&) = delete;
704  auto operator=(enumeration&&) = delete;
705 
706  ~enumeration() = default;
707 
708  private:
710  : idx(i) {}
711 
712  public:
713  auto index() const noexcept -> std::size_t { return idx; }
714 
715  auto copied() & noexcept -> std::remove_const_t<T>& {
716  assert(source != detail_enumerate::get_magic_ptr<T>());
717  assert(local);
718  return *local;
719  }
720  auto copied() const& noexcept -> const T& {
721  assert(source != detail_enumerate::get_magic_ptr<T>());
722  return detail_enumerate::get_or(local, source);
723  }
724 
725  auto reffed() & noexcept -> T& {
726  assert(source != detail_enumerate::get_magic_ptr<T>());
727  return detail_enumerate::get_or(local, source);
728  }
729  auto reffed() const& noexcept -> const T& {
730  assert(source != detail_enumerate::get_magic_ptr<T>());
731  return detail_enumerate::get_or(local, source);
732  }
733 
734  private:
735  auto set(T* t) & -> void { source = t; }
736 
737  auto advance() & noexcept -> void {
738  ++idx;
739  source = detail_enumerate::get_magic_ptr<T>();
740  local = std::nullopt;
741  }
742 
743  std::size_t idx = 0;
744  mutable std::optional<std::remove_const_t<T>> local = std::nullopt;
745  T* source = detail_enumerate::get_magic_ptr<T>();
746 
747  template <typename>
748  friend class enumerator_iterator;
749 };
750 } // namespace kblib
751 
752 namespace std {
753 # if defined(__clang__)
754 // Fix from: https://github.com/nlohmann/json/issues/1401
755 # pragma clang diagnostic push
756 # pragma clang diagnostic ignored "-Wmismatched-tags"
757 # endif
758 
759 template <typename T>
760 class tuple_size<::kblib::enumeration<T>>
761  : public std::integral_constant<std::size_t, 2> {};
762 
763 template <typename T>
764 class tuple_element<0, ::kblib::enumeration<T>> {
765  public:
766  using type = std::size_t;
767 };
768 template <typename T>
769 class tuple_element<0, volatile ::kblib::enumeration<T>> {
770  public:
771  using type = std::size_t;
772 };
773 template <typename T>
774 class tuple_element<0, const volatile ::kblib::enumeration<T>> {
775  public:
776  using type = const std::size_t;
777 };
778 
782 template <typename T>
783 class tuple_element<1, volatile ::kblib::enumeration<T>> {
784  public:
785  using type = T;
786 };
790 template <typename T>
791 class tuple_element<1, const volatile ::kblib::enumeration<T>> {
792  public:
793  using type = const T;
794 };
798 template <typename T>
799 class tuple_element<1, ::kblib::enumeration<T>> {
800  public:
801  using type = std::remove_const_t<T>;
802 };
806 template <typename T>
807 class tuple_element<1, const ::kblib::enumeration<T>> {
808  public:
809  using type = const T;
810 };
811 
812 # if defined(__clang__)
813 # pragma clang diagnostic pop
814 # endif
815 
816 } // namespace std
817 
818 namespace kblib {
819 
820 // When a structured binding is created by value, this function is called as if
821 // by get<i>(std::move(e)), so it does not call the lvalue reference function.
822 // I have no idea why it's implicitly moved, but it works for my purposes.
823 template <std::size_t I, typename T>
824 auto get(enumeration<T>&& e) -> decltype(auto) {
825  static_assert(I <= 1, "enumeration only has two elements");
826  if constexpr (I == 0) {
827  return e.index();
828  } else {
829  return e.copied();
830  }
831 }
832 template <std::size_t I, typename T>
833 auto get(const enumeration<T>&& e) -> decltype(auto) {
834  static_assert(I <= 1, "enumeration only has two elements");
835  if constexpr (I == 0) {
836  return e.index();
837  } else {
838  return e.copied();
839  }
840 }
841 // When captured by reference, the volatile qualifier is added, which allows
842 // std::tuple_element to detect the copying-nonconst-from-const case.
843 template <std::size_t I, typename T>
844 auto get(volatile enumeration<T>& e) -> decltype(auto) {
845  static_assert(I <= 1, "enumeration only has two elements");
846  if constexpr (I == 0) {
847  return const_cast<enumeration<T>&>(e).index();
848  } else {
849  return const_cast<enumeration<T>&>(e).reffed();
850  }
851 }
852 
853 template <std::size_t I, typename T>
854 auto get(const volatile enumeration<T>& e) -> decltype(auto) {
855  static_assert(I <= 1, "enumeration only has two elements");
856  if constexpr (I == 0) {
857  return const_cast<const enumeration<T>&>(e).index();
858  } else {
859  return const_cast<const enumeration<T>&>(e).reffed();
860  }
861 }
862 
863 template <typename It>
865  public:
868  typename std::iterator_traits<It>::value_type>;
869 
871  using difference_type = std::ptrdiff_t;
872  using pointer = const value_type*;
873  using reference = const value_type&;
874  using iterator_category = std::input_iterator_tag;
875 
876  enumerator_iterator() = default;
878  : enumerator_iterator(detail_enumerate::force_copy_tag{},
879  other.curr_.idx, other.it_) {}
881  : it_(it) {}
882 
886 
887  ~enumerator_iterator() = default;
888 
889  auto operator*() & -> volatile value_type& {
890  if (not captured) {
891  curr_.set(to_pointer(it_));
892  captured = true;
893  }
894  return curr_;
895  }
897  curr_.advance();
898  captured = false;
899  ++it_;
900  return *this;
901  }
902 
903  friend auto operator==(const enumerator_iterator& lhs,
904  const enumerator_iterator& rhs) noexcept -> bool {
905  return lhs.it_ == rhs.it_;
906  }
907  friend auto operator!=(const enumerator_iterator& lhs,
908  const enumerator_iterator& rhs) noexcept -> bool {
909  return lhs.it_ != rhs.it_;
910  }
911 
912  private:
914  It it)
915  : it_(it)
916  , curr_(t, idx) {}
917 
918  It it_;
919  bool captured = false;
920  value_type curr_;
921 };
922 
923 template <typename Range, typename = void>
924 class enumerator_t;
925 
926 template <typename Range>
927 class enumerator_t<Range, void> {
928  public:
930 
931  using range_t = typename std::remove_reference_t<Range>;
932  using nested_iterator = decltype(r.begin());
933  using nested_end_iterator = decltype(r.end());
936 
937  using nested_const_iterator = typename range_t::const_iterator;
939 
940  auto begin() const& noexcept(noexcept(r.cbegin())) -> const_iterator {
941  return r.cbegin();
942  }
943  auto begin() & noexcept(noexcept(r.begin())) -> iterator {
944  return r.begin();
945  }
946 
947  auto end() const& noexcept(noexcept(r.cend())) -> const_iterator {
948  return r.cend();
949  }
950  auto end() & noexcept(noexcept(r.end())) -> end_iterator { return r.end(); }
951 };
952 
953 template <typename It, typename EndIt>
955  public:
956  using nested_iterator = It;
959 
960  auto begin() const& noexcept -> iterator { return {r_begin}; }
961 
962  auto end() const& noexcept -> end_iterator { return {r_end}; }
963 
965  EndIt r_end;
966 };
967 
987 template <typename It, typename EIt>
988 auto magic_enumerate(It begin, EIt end) -> enumerator_t<It, EIt> {
989  return {begin, end};
990 }
991 
1012 template <typename Range>
1013 auto magic_enumerate(Range&& r) -> auto {
1014  if constexpr (std::is_lvalue_reference_v<Range&&>) {
1015  using std::begin;
1016  using std::end;
1017  return magic_enumerate(begin(r), end(r));
1018  } else {
1019  return enumerator_t<Range&&>{std::forward<Range>(r)};
1020  }
1021 }
1022 
1023 #endif
1024 
1028 template <typename Iter1, typename Iter2>
1030  Iter1 begin_;
1031  Iter2 end_;
1032 
1033  using value_type = decltype(*begin_);
1034 
1035  constexpr auto begin() const noexcept -> Iter1 { return begin_; }
1036  constexpr auto end() const noexcept -> Iter2 { return end_; }
1037  constexpr auto rbegin() const noexcept -> auto {
1038  return std::make_reverse_iterator(begin_);
1039  }
1040  constexpr auto rend() const noexcept -> auto {
1041  return std::make_reverse_iterator(end_);
1042  }
1043 
1044  constexpr friend auto begin(const indirect_range& r) noexcept -> Iter1 {
1045  return r.begin_;
1046  }
1047  constexpr friend auto end(const indirect_range& r) noexcept -> Iter2 {
1048  return r.end_;
1049  }
1050 };
1051 
1058 template <typename Iter1, typename Iter2>
1059 constexpr auto indirect(Iter1 begin, Iter2 end) noexcept(noexcept(
1060  indirect_range<Iter1, Iter2>{begin, end})) -> indirect_range<Iter1, Iter2> {
1061  return {begin, end};
1062 }
1063 
1064 #if KBLIB_USE_CXX17
1065 
1066 template <typename Iter1, typename Iter2>
1068 
1069 template <typename Iter1, typename Iter2>
1070 auto cry_enumerate(Iter1 begin, Iter2 end) -> auto {
1071  return cry_enumerate(indirect_range{begin, end});
1072 }
1073 
1074 #endif
1075 
1076 // Fixed number of ranges
1077 template <typename Iter1, typename EndIter = Iter1, std::size_t count = 0>
1079  public:
1080  private:
1081  struct range {
1082  Iter1 begin;
1083  EndIter end;
1084  };
1085 
1086  std::array<range, count> ranges;
1087 };
1088 
1089 // Dynamic number of ranges
1090 template <typename Iter1, typename EndIter>
1091 class multi_range<Iter1, EndIter, 0> {
1092  public:
1093  private:
1094  struct range {
1095  Iter1 begin;
1096  EndIter end;
1097  };
1098 
1099  std::vector<range> ranges;
1100 };
1101 
1107 template <typename T>
1112  constexpr auto operator*() noexcept -> T& { return val; }
1116  constexpr auto operator*() const noexcept -> const T& { return val; }
1117 
1121  constexpr auto operator->() noexcept -> T* { return &val; }
1125  constexpr auto operator->() const noexcept -> const T* { return &val; }
1126 
1130  constexpr auto get() noexcept -> T* { return &val; }
1134  constexpr auto get() const noexcept -> const T* { return &val; }
1135 
1136  T val;
1137 };
1138 
1139 #if KBLIB_USE_CXX17
1140 
1147 template <typename base_iterator, typename operation>
1149  private:
1150  base_iterator it;
1151  operation op;
1152 
1153  public:
1154  using difference_type = std::ptrdiff_t;
1155  using result_type = decltype(kblib::invoke(op, *it));
1157  = decltype(kblib::invoke(std::as_const(op), *std::as_const(it)));
1159  using pointer = void;
1161  using iterator_category = std::input_iterator_tag;
1162 
1170  transform_iterator(base_iterator _it,
1171  operation _op) noexcept(noexcept(base_iterator{
1172  _it}) and noexcept(std::is_nothrow_move_constructible<operation>::value))
1173  : it(_it)
1174  , op(std::move(_op)) {}
1175 
1181  transform_iterator(base_iterator end_it) noexcept(noexcept(base_iterator{
1182  end_it}))
1183  : it(end_it)
1184  , op() {}
1185 
1191  auto operator*() noexcept(noexcept(kblib::invoke(op, *it)))
1192  -> decltype(auto) {
1193  return kblib::invoke(op, *it);
1194  }
1200  decltype(auto) operator*() const noexcept(noexcept(kblib::invoke(op, *it))) {
1201  return kblib::invoke(op, *it);
1202  }
1203 
1208  auto operator->() noexcept(noexcept(kblib::invoke(op, *it))) -> auto {
1209  return containing_ptr<result_type>{{kblib::invoke(op, *it)}};
1210  }
1215  auto operator->() const noexcept(noexcept(kblib::invoke(op, *it))) -> auto {
1217  }
1218 
1222  auto operator++() noexcept(noexcept(++it)) -> transform_iterator& {
1223  ++it;
1224  return *this;
1225  }
1226 
1231  [[deprecated("Needlessly copies op. Use preincrement instead.")]] auto
1232  operator++(int) noexcept(noexcept(transform_iterator{it++, op}))
1233  -> transform_iterator {
1234  return {it++, op};
1235  }
1236 
1237  auto base() const noexcept -> base_iterator { return it; }
1238 
1242  friend auto operator==(const transform_iterator& lhs,
1243  const transform_iterator& rhs) noexcept -> bool {
1244  return lhs.it == rhs.it;
1245  }
1246 
1250  friend auto operator!=(const transform_iterator& lhs,
1251  const transform_iterator& rhs) noexcept -> bool {
1252  return lhs.it != rhs.it;
1253  }
1254 
1255  template <typename OIt>
1256  friend auto operator==(const transform_iterator& lhs,
1257  const OIt& rhs) noexcept -> bool {
1258  return lhs.base() == rhs;
1259  }
1260  template <typename OIt>
1261  friend auto operator==(const OIt& lhs,
1262  const transform_iterator& rhs) noexcept -> bool {
1263  return lhs == rhs.base();
1264  }
1265 
1266  template <typename OIt>
1267  friend auto operator!=(const transform_iterator& lhs,
1268  const OIt& rhs) noexcept -> bool {
1269  return lhs.base() != rhs;
1270  }
1271  template <typename OIt>
1272  friend auto operator!=(const OIt& lhs,
1273  const transform_iterator& rhs) noexcept -> bool {
1274  return lhs != rhs.base();
1275  }
1276 };
1277 
1278 template <typename It, typename operation>
1280 
1290 template <typename base_iterator, typename operation>
1291 [[deprecated("use transformer instead")]] auto make_transform_iterator(
1292  base_iterator it,
1293  operation
1294  op) noexcept(noexcept(transform_iterator<base_iterator, operation>{
1295  it, std::move(op)})) -> transform_iterator<base_iterator, operation> {
1296  return {it, std::move(op)};
1297 }
1298 
1306 template <typename base_iterator, typename operation>
1307 auto transformer(base_iterator it, operation op) noexcept(
1308  noexcept(transform_iterator<base_iterator, operation>{it, std::move(op)}))
1309  -> transform_iterator<base_iterator, operation> {
1310  return {it, std::move(op)};
1311 }
1312 
1313 template <typename It, typename EndIt, typename operation>
1314 auto transform_range(It begin, EndIt end, operation op) noexcept(
1315  noexcept(indirect(transform_iterator{begin, op}, end))) -> auto {
1316  return indirect(transform_iterator{begin, op}, end);
1317 }
1318 #endif
1319 
1320 template <typename InputIt1, typename EndIt, typename InputIt2>
1322  InputIt1 pos1{};
1323  EndIt end1{};
1324  InputIt2 pos2{};
1325 
1326  constexpr static bool is_nothrow_copyable
1327  = std::is_nothrow_copy_constructible<InputIt1>::value
1328  and std::is_nothrow_copy_constructible<EndIt>::value
1329  and std::is_nothrow_copy_constructible<InputIt2>::value;
1330 
1331  auto operator++() noexcept(noexcept(++pos1) and noexcept(++pos2))
1332  -> zip_iterator& {
1333  ++pos1;
1334  ++pos2;
1335  return *this;
1336  }
1337  auto operator++(int) noexcept(is_nothrow_copyable and noexcept(
1338  ++pos1) and noexcept(++pos2)) -> const zip_iterator {
1339  auto tmp = *this;
1340  ++pos1;
1341  ++pos2;
1342  return tmp;
1343  }
1344 
1345  KBLIB_NODISCARD auto operator*() const noexcept -> auto {
1346  return std::forward_as_tuple(*pos1, *pos2);
1347  }
1348 
1350  -> zip_iterator {
1351  return *this;
1352  }
1353  KBLIB_NODISCARD auto end() const
1354  noexcept(std::is_nothrow_copy_constructible<EndIt>::value and
1355  std::is_nothrow_copy_constructible<InputIt2>::value)
1356  -> zip_iterator<EndIt, EndIt, InputIt2> {
1357  return {end1, end1};
1358  }
1359 
1361  const zip_iterator& z1,
1362  const zip_iterator& z2) noexcept(noexcept(z1.pos1 == z2.pos1)) -> bool {
1363  return z1.pos1 == z2.pos1;
1364  }
1366  const zip_iterator& z1,
1367  const zip_iterator& z2) noexcept(noexcept(z1.pos1 != z2.pos1)) -> bool {
1368  return z1.pos1 != z2.pos1;
1369  }
1371  const zip_iterator& z1,
1372  zip_iterator<EndIt, EndIt, InputIt2> end) noexcept(noexcept(z1.pos1
1373  == end.val))
1374  -> bool {
1375  return z1.end1 == end.val;
1376  }
1378  const zip_iterator& z1,
1379  zip_iterator<EndIt, EndIt, InputIt2> end) noexcept(noexcept(z1.pos1
1380  == end.val))
1381  -> bool {
1382  return z1.end1 != end.val;
1383  }
1384 };
1385 
1386 template <typename It1, typename It2>
1387 struct zip_iterator<It1, It1, It2> {
1388  It1 pos1{};
1389  It1 end1{};
1390  It2 pos2{};
1391 
1392  constexpr static bool is_nothrow_copyable
1393  = std::is_nothrow_copy_constructible<It1>::value
1394  and std::is_nothrow_copy_constructible<It2>::value;
1395 
1396  auto operator++() noexcept(noexcept(++pos1)) -> zip_iterator& {
1397  ++pos1;
1398  ++pos2;
1399  return *this;
1400  }
1401  auto operator++(int) noexcept(is_nothrow_copyable and noexcept(++pos1))
1402  -> const zip_iterator {
1403  auto tmp = *this;
1404  ++pos1;
1405  ++pos2;
1406  return tmp;
1407  }
1408 
1409  KBLIB_NODISCARD auto operator*() -> auto {
1410  return std::forward_as_tuple(*pos1, *pos2);
1411  }
1412 
1414  -> zip_iterator {
1415  return *this;
1416  }
1417  KBLIB_NODISCARD auto end() const
1418  noexcept(std::is_nothrow_copy_constructible<It1>::value)
1419  -> zip_iterator {
1420  return {end1, end1, pos2};
1421  }
1422 
1424  const zip_iterator& z1,
1425  const zip_iterator& z2) noexcept(noexcept(z1.pos1 == z2.pos1)) -> bool {
1426  return z1.pos1 == z2.pos1;
1427  }
1429  const zip_iterator& z1,
1430  const zip_iterator& z2) noexcept(noexcept(z1.pos1 == z2.pos1)) -> bool {
1431  return z1.pos1 != z2.pos1;
1432  }
1433 };
1434 
1446 template <typename InputIt1, typename EndIt, typename InputIt2>
1447 KBLIB_NODISCARD auto zip(InputIt1 begin1, EndIt end1, InputIt2 begin2) noexcept(
1450  return {begin1, end1, begin2};
1451 }
1452 
1462 template <typename Range1, typename Range2>
1463 KBLIB_NODISCARD auto zip(Range1&& r1, Range2&& r2) noexcept(
1464  zip_iterator<decltype(begin(r1)), decltype(end(r1)),
1465  decltype(begin(r2))>::is_nothrow_copyable)
1466  -> zip_iterator<decltype(begin(r1)), decltype(end(r1)),
1467  decltype(begin(r2))> {
1468  return {begin(r1), end(r1), begin(r2)};
1469 }
1470 
1472 template <typename ForwardIt, typename EndIt>
1474  public:
1475  using difference_type = std::ptrdiff_t;
1476  using base_reference = typename std::iterator_traits<ForwardIt>::reference;
1477  using value_type = std::pair<base_reference, base_reference>;
1478  using pointer = void;
1480  using iterator_category = std::input_iterator_tag;
1481 
1482  private:
1483  ForwardIt it;
1484 };
1485 
1492 template <typename Container, typename F>
1494  public:
1501  explicit back_insert_iterator_F(Container& c, F f)
1502  : container(c)
1503  , fun(std::move(f)) {}
1504 
1505  using value_type = void;
1506  using difference_type = void;
1507  using pointer = void;
1508  using reference = void;
1509  using iterator_category = std::output_iterator_tag;
1510 
1511  template <typename V>
1519  auto operator=(V&& value) -> back_insert_iterator_F& {
1520  container.push_back(invoke(fun, std::forward<V>(value)));
1521  return *this;
1522  }
1523 
1527  auto operator*() -> back_insert_iterator_F& { return *this; }
1531  auto operator++() -> back_insert_iterator_F& { return *this; }
1532 
1533  private:
1534  Container& container;
1535  F fun;
1536 };
1537 
1542 template <typename F>
1544  private:
1545  F fun;
1546 
1547  public:
1548  using value_type = void;
1549  using difference_type = void;
1550  using pointer = void;
1551  using reference = void;
1552  using iterator_category = std::output_iterator_tag;
1553 
1559  explicit consume_iterator(F f)
1560  : fun(std::move(f)) {}
1561 
1568  template <typename V>
1569  auto operator=(V&& value) noexcept(noexcept(
1570  kblib::invoke(fun, std::forward<V>(value)))) -> consume_iterator& {
1571  kblib::invoke(fun, std::forward<V>(value));
1572  return *this;
1573  }
1574 
1578  auto operator*() -> consume_iterator& { return *this; }
1582  auto operator++() -> consume_iterator& { return *this; }
1586  auto operator++(int) -> consume_iterator& { return *this; }
1587 };
1588 
1598 template <typename F>
1600  return consume_iterator<F>{std::move(f)};
1601 }
1602 
1603 } // namespace kblib
1604 
1605 #endif // KBLIB_ITERATORS_H
TODO(killerbee13): Implement adjacent_iterator.
Definition: iterators.h:1473
std::input_iterator_tag iterator_category
Definition: iterators.h:1480
std::ptrdiff_t difference_type
Definition: iterators.h:1475
std::pair< base_reference, base_reference > value_type
Definition: iterators.h:1477
typename std::iterator_traits< ForwardIt >::reference base_reference
Definition: iterators.h:1476
An OutputIterator that transforms the values assigned to it before inserting them into the back of a ...
Definition: iterators.h:1493
std::output_iterator_tag iterator_category
Definition: iterators.h:1509
auto operator*() -> back_insert_iterator_F &
A no-op.
Definition: iterators.h:1527
auto operator=(V &&value) -> back_insert_iterator_F &
Calls container.push_back(kblib::invoke(fun, std::forward<V>(value)));.
Definition: iterators.h:1519
back_insert_iterator_F(Container &c, F f)
Definition: iterators.h:1501
auto operator++() -> back_insert_iterator_F &
A no-op.
Definition: iterators.h:1531
An OutputIterator that simply calls a provided functor for each value assigned to it.
Definition: iterators.h:1543
std::output_iterator_tag iterator_category
Definition: iterators.h:1552
consume_iterator(F f)
Constructs a consume_iterator with the given function object.
Definition: iterators.h:1559
auto operator=(V &&value) noexcept(noexcept(kblib::invoke(fun, std::forward< V >(value)))) -> consume_iterator &
Pass value to F.
Definition: iterators.h:1569
auto operator++(int) -> consume_iterator &
A no-op.
Definition: iterators.h:1586
auto operator++() -> consume_iterator &
A no-op.
Definition: iterators.h:1582
auto operator*() -> consume_iterator &
A no-op.
Definition: iterators.h:1578
Like a std::back_insert_iterator, but it keeps track of how many insertions it has made,...
Definition: iterators.h:106
friend auto operator>=(const counting_back_insert_iterator &a, const counting_back_insert_iterator &b) noexcept -> bool
Definition: iterators.h:184
friend auto operator==(const counting_back_insert_iterator &a, const counting_back_insert_iterator &b) noexcept -> bool
Definition: iterators.h:159
auto operator++(int) noexcept -> counting_back_insert_iterator=delete
friend auto operator-(const counting_back_insert_iterator &a, const counting_back_insert_iterator &b) noexcept -> std::ptrdiff_t
Definition: iterators.h:189
friend auto operator<(const counting_back_insert_iterator &a, const counting_back_insert_iterator &b) noexcept -> bool
Definition: iterators.h:169
friend auto operator>(const counting_back_insert_iterator &a, const counting_back_insert_iterator &b) noexcept -> bool
Definition: iterators.h:179
auto operator++() &noexcept -> counting_back_insert_iterator &
Definition: iterators.h:151
friend auto operator!=(const counting_back_insert_iterator &a, const counting_back_insert_iterator &b) noexcept -> bool
Definition: iterators.h:164
counting_back_insert_iterator() noexcept=default
auto operator*() noexcept -> proxy_iterator
Definition: iterators.h:146
counting_back_insert_iterator(std::size_t n)
Definition: iterators.h:118
std::output_iterator_tag iterator_category
Definition: iterators.h:112
friend auto operator<=(const counting_back_insert_iterator &a, const counting_back_insert_iterator &b) noexcept -> bool
Definition: iterators.h:174
auto operator=(const enumeration &)=delete
auto copied() &noexcept -> std::remove_const_t< T > &
Definition: iterators.h:715
auto operator=(enumeration &&)=delete
auto reffed() &noexcept -> T &
Definition: iterators.h:725
auto index() const noexcept -> std::size_t
Definition: iterators.h:713
enumeration(volatile enumeration &other)
Definition: iterators.h:699
auto copied() const &noexcept -> const T &
Definition: iterators.h:720
auto reffed() const &noexcept -> const T &
Definition: iterators.h:729
~enumeration()=default
enumeration(const enumeration &other)
Definition: iterators.h:691
enumeration()=default
enumeration(enumeration &&)=delete
enumeration< nested_value > value_type
Definition: iterators.h:870
enumerator_iterator(const enumerator_iterator &other)
Definition: iterators.h:877
auto operator++() &-> enumerator_iterator &
Definition: iterators.h:896
auto operator=(enumerator_iterator &&) -> enumerator_iterator &=default
friend auto operator==(const enumerator_iterator &lhs, const enumerator_iterator &rhs) noexcept -> bool
Definition: iterators.h:903
std::input_iterator_tag iterator_category
Definition: iterators.h:874
auto operator=(const enumerator_iterator &) -> enumerator_iterator &=default
std::ptrdiff_t difference_type
Definition: iterators.h:871
copy_const_t< decltype(*std::declval< It & >()), typename std::iterator_traits< It >::value_type > nested_value
Definition: iterators.h:868
auto operator*() &-> volatile value_type &
Definition: iterators.h:889
enumerator_iterator(enumerator_iterator &&)=default
friend auto operator!=(const enumerator_iterator &lhs, const enumerator_iterator &rhs) noexcept -> bool
Definition: iterators.h:907
typename range_t::const_iterator nested_const_iterator
Definition: iterators.h:937
auto end() &noexcept(noexcept(r.end())) -> end_iterator
Definition: iterators.h:950
typename std::remove_reference_t< Range > range_t
Definition: iterators.h:931
decltype(r.begin()) nested_iterator
Definition: iterators.h:932
auto begin() const &noexcept(noexcept(r.cbegin())) -> const_iterator
Definition: iterators.h:940
auto begin() &noexcept(noexcept(r.begin())) -> iterator
Definition: iterators.h:943
decltype(r.end()) nested_end_iterator
Definition: iterators.h:933
detail::no_dangle_t< Range > r
Definition: iterators.h:929
auto end() const &noexcept(noexcept(r.cend())) -> const_iterator
Definition: iterators.h:947
auto end() const &noexcept -> end_iterator
Definition: iterators.h:962
auto begin() const &noexcept -> iterator
Definition: iterators.h:960
constexpr static bool nothrow_steppable
Definition: iterators.h:655
constexpr static bool nothrow_copyable
Definition: iterators.h:654
A range generator, similar to Python 3's range().
Definition: iterators.h:221
constexpr auto operator[](Integral x) const noexcept -> decltype(begin()[x])
Definition: iterators.h:415
constexpr friend auto begin(const range_t &r) noexcept -> iterator
Returns an iterator to the beginning of the range.
Definition: iterators.h:392
constexpr auto lesser() const noexcept(nothrow_copyable) -> Value
Definition: iterators.h:420
constexpr auto end() const noexcept -> iterator
Return an iterator to the end of the range.
Definition: iterators.h:380
constexpr auto empty() const noexcept -> bool
Query whether the range will generate any elements.
Definition: iterators.h:412
constexpr auto greater() const noexcept(nothrow_copyable) -> Value
Definition: iterators.h:424
constexpr auto size() const noexcept -> std::size_t
Returns the distance between start() and stop().
Definition: iterators.h:385
constexpr range_t(Value max_)
1-argument constructor. Start is implicitly zero and step is 1 or -1, depending on the sign of max.
Definition: iterators.h:251
constexpr friend auto operator==(range_t l, range_t r) noexcept -> bool
Compare l and r for equality.
Definition: iterators.h:461
constexpr friend auto operator!=(range_t l, range_t r) noexcept -> bool
Compare l and r for inequality.
Definition: iterators.h:471
constexpr friend auto size(const range_t &r) noexcept -> std::size_t
Returns the distance between start() and stop().
Definition: iterators.h:405
constexpr auto begin() const noexcept -> iterator
Returns an iterator to the beginning of the range.
Definition: iterators.h:376
constexpr range_t(Value min_, Value max_, Delta step_=1)
2- and 3-argument constructor. Explicitly specify start, end, and optionally the step amount.
Definition: iterators.h:239
constexpr friend auto end(const range_t &r) noexcept -> iterator
Return an iterator to the end of the range.
Definition: iterators.h:398
An InputIterator that applies a transformation to the elements of the range.
Definition: iterators.h:1148
std::ptrdiff_t difference_type
Definition: iterators.h:1154
decltype(kblib::invoke(std::as_const(op), *std::as_const(it))) const_result_type
Definition: iterators.h:1157
auto operator->() const noexcept(noexcept(kblib::invoke(op, *it))) -> auto
Returns a containing_ptr with the transformed value, because operator-> expects a pointer-like return...
Definition: iterators.h:1215
transform_iterator(base_iterator _it, operation _op) noexcept(noexcept(base_iterator{ _it}) and noexcept(std::is_nothrow_move_constructible< operation >::value))
Constructs a transform_iterator which applies _op to the values obtained from *_it.
Definition: iterators.h:1170
friend auto operator==(const OIt &lhs, const transform_iterator &rhs) noexcept -> bool
Definition: iterators.h:1261
transform_iterator(base_iterator end_it) noexcept(noexcept(base_iterator{ end_it}))
constructs a non-dereferenceable sentinel iterator
Definition: iterators.h:1181
friend auto operator==(const transform_iterator &lhs, const OIt &rhs) noexcept -> bool
Definition: iterators.h:1256
auto operator++() noexcept(noexcept(++it)) -> transform_iterator &
Increments the underlying iterator and returns *this.
Definition: iterators.h:1222
auto operator->() noexcept(noexcept(kblib::invoke(op, *it))) -> auto
Returns a containing_ptr with the transformed value, because operator-> expects a pointer-like return...
Definition: iterators.h:1208
friend auto operator!=(const OIt &lhs, const transform_iterator &rhs) noexcept -> bool
Definition: iterators.h:1272
auto operator++(int) noexcept(noexcept(transform_iterator{it++, op})) -> transform_iterator
Increments the underlying iterator and returns a copy of the current value.
Definition: iterators.h:1232
decltype(kblib::invoke(op, *it)) result_type
Definition: iterators.h:1155
std::input_iterator_tag iterator_category
Definition: iterators.h:1161
auto operator*() noexcept(noexcept(kblib::invoke(op, *it))) -> decltype(auto)
Transforms the value obtained by dereferencing it.
Definition: iterators.h:1191
friend auto operator==(const transform_iterator &lhs, const transform_iterator &rhs) noexcept -> bool
Compares the base iterators of lhs and rhs.
Definition: iterators.h:1242
auto base() const noexcept -> base_iterator
Definition: iterators.h:1237
friend auto operator!=(const transform_iterator &lhs, const OIt &rhs) noexcept -> bool
Definition: iterators.h:1267
friend auto operator!=(const transform_iterator &lhs, const transform_iterator &rhs) noexcept -> bool
Compares the base iterators of lhs and rhs.
Definition: iterators.h:1250
This header provides some features of C++17 <type_traits> and other headers for C++14,...
auto get_magic_ptr() -> T *
Definition: iterators.h:678
auto get_or(T1 &&t1, T2 &&t2) -> decltype(auto)
Definition: iterators.h:670
typename no_dangle< T >::type no_dangle_t
Definition: tdecl.h:161
typename make_void< Ts... >::type void_t
Definition: fakestd.h:178
constexpr struct kblib::nums::min_t min
constexpr struct kblib::nums::max_t max
The main namespace in which all entities from kblib are defined.
Definition: algorithm.h:44
auto magic_enumerate(It begin, EIt end) -> enumerator_t< It, EIt >
Allow access to indexes while using range-based for loops.
Definition: iterators.h:988
auto transformer(base_iterator it, operation op) noexcept(noexcept(transform_iterator< base_iterator, operation >{it, std::move(op)})) -> transform_iterator< base_iterator, operation >
Factory function to make transform_iterators.
Definition: iterators.h:1307
auto zip(InputIt1 begin1, EndIt end1, InputIt2 begin2) noexcept(zip_iterator< InputIt1, EndIt, InputIt2 >::is_nothrow_copyable) -> zip_iterator< InputIt1, EndIt, InputIt2 >
Iterate over two ranges in lockstep, like Python's zip.
Definition: iterators.h:1447
auto transform_range(It begin, EndIt end, operation op) noexcept(noexcept(indirect(transform_iterator{begin, op}, end))) -> auto
Definition: iterators.h:1314
auto consumer(F f) -> consume_iterator< F >
Creates a consume_iterator of deduced type F.
Definition: iterators.h:1599
constexpr auto to_signed(I x) -> std::make_signed_t< I >
Cast integral argument to corresponding signed type.
Definition: fakestd.h:592
constexpr auto to_pointer(P &&p) noexcept -> auto *
Gets a raw pointer out of any smart pointer or iterator you might pass in, without dereferencing it o...
Definition: iterators.h:71
constexpr auto a(const std::initializer_list< T > &a) -> auto
Index an array literal without naming its type.
Definition: simple.h:255
typename std::enable_if< B, T >::type enable_if_t
Definition: fakestd.h:54
constexpr auto operator+(T val, adjuster a) noexcept -> enable_if_t< not detail_iterators::is_addable< T, std::ptrdiff_t >::value, decltype(std::advance(val, a.adj))>
Definition: iterators.h:552
constexpr auto e() -> T
Definition: stats.h:465
auto cry_enumerate(Range &&range) -> auto
constexpr auto range(Value min, Value max, Delta step=0) -> range_t< Value, Delta >
Constructs a range from beginning, end, and step amount. The range is half-open, that is min is in th...
Definition: iterators.h:620
constexpr auto irange(Value, Value, Delta=0)
Definition: iterators.h:659
counting_back_insert_iterator< C > counting_back_inserter(C &c, std::size_t count=0)
Definition: iterators.h:202
constexpr auto max_element(ForwardIt first, EndIt last, Compare comp={}) -> ForwardIt
Definition: algorithm.h:1109
constexpr auto indirect(Iter1 begin, Iter2 end) noexcept(noexcept(indirect_range< Iter1, Iter2 >{begin, end})) -> indirect_range< Iter1, Iter2 >
Create a range from an iterator pair. Primarily useful for range-for loops.
Definition: iterators.h:1059
auto get(punner< Types... > &p) noexcept -> decltype(auto)
Definition: bits.h:730
constexpr auto invoke(F &&f, Args &&... args) noexcept(noexcept(detail::do_invoke(std::forward< F >(f), std::forward< Args >(args)...))) -> decltype(auto)
Definition: fakestd.h:130
transform_iterator(It, operation) -> transform_iterator< It, operation >
typename value_type_linear< Container >::type value_type_linear_t
Definition: fakestd.h:933
indirect_range(Iter1, Iter2) -> indirect_range< Iter1, Iter2 >
auto make_transform_iterator(base_iterator it, operation op) noexcept(noexcept(transform_iterator< base_iterator, operation >{ it, std::move(op)})) -> transform_iterator< base_iterator, operation >
Factory function to make transform_iterators.
Definition: iterators.h:1291
typename copy_const< C, V >::type copy_const_t
Definition: fakestd.h:870
Definition: bits.h:714
constexpr adjuster(std::ptrdiff_t adj_) noexcept
Definition: iterators.h:546
std::ptrdiff_t adj
Definition: iterators.h:545
A smart pointer to an object contained inside the smart pointer object.
Definition: iterators.h:1108
constexpr auto operator*() const noexcept -> const T &
Returns the contained object.
Definition: iterators.h:1116
constexpr auto operator->() const noexcept -> const T *
Return the address of the contained object.
Definition: iterators.h:1125
constexpr auto operator->() noexcept -> T *
Return the address of the contained object.
Definition: iterators.h:1121
constexpr auto get() noexcept -> T *
Returns the address of the contained object.
Definition: iterators.h:1130
constexpr auto operator*() noexcept -> T &
Returns the contained object.
Definition: iterators.h:1112
constexpr auto get() const noexcept -> const T *
Returns the address of the contained object.
Definition: iterators.h:1134
auto operator=(value_type &&value) &-> proxy_iterator &
Definition: iterators.h:133
auto operator=(const value_type &value) &-> proxy_iterator &
Definition: iterators.h:124
typename Container::value_type value_type
Definition: iterators.h:122
A struct which decrements anything it is added to. Suitable for use as a Delta type for range_t.
Definition: iterators.h:588
constexpr friend auto operator*(std::ptrdiff_t x, decrementer)
Definition: iterators.h:592
constexpr decrementer() noexcept=default
constexpr auto operator()(T &t) -> T &
Definition: iterators.h:596
A struct which increments anything it is added to. Suitable for use as a Delta type for range_t.
Definition: iterators.h:562
constexpr friend auto operator*(std::ptrdiff_t x, incrementer)
Definition: iterators.h:566
constexpr incrementer() noexcept=default
constexpr auto operator()(T &t) -> T &
Definition: iterators.h:571
Allow range-for iteration of an iterator pair.
Definition: iterators.h:1029
constexpr auto rend() const noexcept -> auto
Definition: iterators.h:1040
constexpr friend auto begin(const indirect_range &r) noexcept -> Iter1
Definition: iterators.h:1044
decltype(*begin_) value_type
Definition: iterators.h:1033
constexpr friend auto end(const indirect_range &r) noexcept -> Iter2
Definition: iterators.h:1047
constexpr auto begin() const noexcept -> Iter1
Definition: iterators.h:1035
constexpr auto end() const noexcept -> Iter2
Definition: iterators.h:1036
constexpr auto rbegin() const noexcept -> auto
Definition: iterators.h:1037
Determine if T is a valid output iterator to which values of type E may be written.
Definition: iterators.h:90
A helper struct which acts as an iterator for the range elements, as they are generated on the fly.
Definition: iterators.h:258
constexpr friend auto operator>(iterator l, iterator r) noexcept -> bool
Compare two range iterators.
Definition: iterators.h:351
constexpr auto operator[](Integral x) const noexcept -> Value
Definition: iterators.h:368
constexpr auto operator++(int) noexcept(nothrow_steppable) -> iterator
Postfix increment. Advance to the next value in the range, but return the current value.
Definition: iterators.h:298
constexpr friend auto operator!=(iterator l, iterator r) noexcept -> bool
Compare two range iterators for inequality.
Definition: iterators.h:319
constexpr friend auto operator<(iterator l, iterator r) noexcept -> bool
Compare two range iterators.
Definition: iterators.h:329
constexpr auto operator*() const noexcept(nothrow_copyable) -> Value
Return the "pointed-to" value.
Definition: iterators.h:273
constexpr friend auto operator>=(iterator l, iterator r) noexcept -> bool
Compare two range iterators.
Definition: iterators.h:360
const Value * pointer
Definition: iterators.h:264
constexpr auto operator[](std::ptrdiff_t x) const noexcept -> Value
Definition: iterators.h:364
constexpr friend auto operator<=(iterator l, iterator r) noexcept -> bool
Compare two range iterators.
Definition: iterators.h:341
std::ptrdiff_t difference_type
Definition: iterators.h:262
constexpr auto operator++() &noexcept(nothrow_steppable) -> iterator &
Prefix increment. Advance to the next value in the range.
Definition: iterators.h:288
constexpr auto operator->() const noexcept -> pointer
Return a pointer to the value.
Definition: iterators.h:282
constexpr friend auto operator==(iterator l, iterator r) noexcept -> bool
Compare two range iterators for equality.
Definition: iterators.h:309
std::input_iterator_tag iterator_category
Definition: iterators.h:266
constexpr auto operator()(T *p) const noexcept -> T *
Definition: iterators.h:61
constexpr auto operator()(const ptr &p) const noexcept -> auto
Definition: iterators.h:54
constexpr auto operator()(ptr &&p) const noexcept -> auto
Definition: iterators.h:51
auto operator++() noexcept(noexcept(++pos1)) -> zip_iterator &
Definition: iterators.h:1396
friend auto operator!=(const zip_iterator &z1, const zip_iterator &z2) noexcept(noexcept(z1.pos1==z2.pos1)) -> bool
Definition: iterators.h:1428
friend auto operator==(const zip_iterator &z1, const zip_iterator &z2) noexcept(noexcept(z1.pos1==z2.pos1)) -> bool
Definition: iterators.h:1423
auto begin() const noexcept(is_nothrow_copyable) -> zip_iterator
Definition: iterators.h:1413
auto operator++(int) noexcept(is_nothrow_copyable and noexcept(++pos1)) -> const zip_iterator
Definition: iterators.h:1401
auto end() const noexcept(std::is_nothrow_copy_constructible< It1 >::value) -> zip_iterator
Definition: iterators.h:1417
auto operator++() noexcept(noexcept(++pos1) and noexcept(++pos2)) -> zip_iterator &
Definition: iterators.h:1331
constexpr static bool is_nothrow_copyable
Definition: iterators.h:1327
friend auto operator==(const zip_iterator &z1, const zip_iterator &z2) noexcept(noexcept(z1.pos1==z2.pos1)) -> bool
Definition: iterators.h:1360
friend auto operator!=(const zip_iterator &z1, zip_iterator< EndIt, EndIt, InputIt2 > end) noexcept(noexcept(z1.pos1==end.val)) -> bool
Definition: iterators.h:1377
friend auto operator!=(const zip_iterator &z1, const zip_iterator &z2) noexcept(noexcept(z1.pos1 !=z2.pos1)) -> bool
Definition: iterators.h:1365
friend auto operator==(const zip_iterator &z1, zip_iterator< EndIt, EndIt, InputIt2 > end) noexcept(noexcept(z1.pos1==end.val)) -> bool
Definition: iterators.h:1370
auto end() const noexcept(std::is_nothrow_copy_constructible< EndIt >::value and std::is_nothrow_copy_constructible< InputIt2 >::value) -> zip_iterator< EndIt, EndIt, InputIt2 >
Definition: iterators.h:1353
auto begin() const noexcept(is_nothrow_copyable) -> zip_iterator
Definition: iterators.h:1349
auto operator*() const noexcept -> auto
Definition: iterators.h:1345
auto operator++(int) noexcept(is_nothrow_copyable and noexcept(++pos1) and noexcept(++pos2)) -> const zip_iterator
Definition: iterators.h:1337
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Definition: tdecl.h:81