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
37#include "fakestd.h"
38#include "traits.h"
39
40#include <cassert>
41#include <iterator>
42#include <vector>
43
44#if KBLIB_USE_CXX17
45# include <optional>
46#endif
47
48namespace KBLIB_NS {
49
50template <typename ptr>
52 constexpr auto operator()(ptr&& p) const noexcept -> auto {
53 return to_pointer_impl<decltype(p.operator->())>{}(p.operator->());
54 }
55 constexpr auto operator()(const ptr& p) const noexcept -> auto {
56 return to_pointer_impl<decltype(p.operator->())>{}(p.operator->());
57 }
58};
59
60template <typename T>
61struct to_pointer_impl<T*> {
62 constexpr auto operator()(T* p) const noexcept -> T* { return p; }
63};
64
71template <typename P>
72constexpr auto to_pointer(P&& p) noexcept -> auto* {
74}
75
76template <typename Container,
77 typename Comp = std::less<value_type_linear_t<Container>>>
78auto max_element(Container& c, Comp comp) -> value_type_linear_t<Container>* {
79 auto it = max_element(std::begin(c), std::end(c), comp);
80 if (it != std::end(c)) {
81 return to_pointer(it);
82 } else {
83 return nullptr;
84 }
85}
90template <typename T, typename E, typename = void>
91struct is_output_iterator_for : std::false_type {};
92
93template <typename T, typename E>
95 T, E, void_t<decltype(*std::declval<T&>()++ = std::declval<const E&>())>>
96 : std::true_type {};
97
98template <typename Container>
108 public:
109 using value_type = void;
110 using difference_type = std::ptrdiff_t;
111 using pointer = void;
112 using reference = void;
113 using iterator_category = std::output_iterator_tag;
114
115 counting_back_insert_iterator() noexcept = default;
116 explicit counting_back_insert_iterator(Container& c, std::size_t n = 0)
117 : container(std::addressof(c))
118 , count(n) {}
119 explicit counting_back_insert_iterator(std::size_t n)
120 : count(n) {}
121
123 using value_type = typename Container::value_type;
124
125 auto operator=(const value_type& value) & -> proxy_iterator& {
126 assert(container);
127 // Multiple assignments for a single dereference are not allowed
128 assert(*dirty);
129 *dirty = false;
130 container->push_back(value);
131 return *this;
132 }
133
134 auto operator=(value_type&& value) & -> proxy_iterator& {
135 assert(container);
136 // Multiple assignments for a single dereference are not allowed
137 assert(*dirty);
138 *dirty = false;
139 container->push_back(std::move(value));
140 return *this;
141 }
142
143 Container* container;
144 bool* dirty;
145 };
146
147 auto operator*() noexcept -> proxy_iterator {
148 assert(dirty);
149 return {container, &dirty};
150 }
151
153 assert(not dirty);
154 ++count;
155 dirty = true;
156 return *this;
157 }
158 auto operator++(int) noexcept -> counting_back_insert_iterator = delete;
159
161 const counting_back_insert_iterator& b) noexcept
162 -> bool {
163 return a.count == b.count;
164 }
166 const counting_back_insert_iterator& b) noexcept
167 -> bool {
168 return a.count != b.count;
169 }
171 const counting_back_insert_iterator& b) noexcept
172 -> bool {
173 return a.count < b.count;
174 }
176 const counting_back_insert_iterator& b) noexcept
177 -> bool {
178 return a.count <= b.count;
179 }
181 const counting_back_insert_iterator& b) noexcept
182 -> bool {
183 return a.count > b.count;
184 }
186 const counting_back_insert_iterator& b) noexcept
187 -> bool {
188 return a.count >= b.count;
189 }
191 const counting_back_insert_iterator& b) noexcept
192 -> std::ptrdiff_t {
193 return std::ptrdiff_t(a.count) - ptrdiff_t(b.count);
194 }
195
196 protected:
197 Container* container = nullptr;
198 std::size_t count = 0;
199 bool dirty = true;
200};
201
202template <typename C>
204 C& c, std::size_t count = 0) {
205 return counting_back_insert_iterator<C>{c, count};
206}
207
221template <typename Value, typename Delta>
222class range_t {
223 private:
224 Value min, max;
225 Delta step;
226
227 constexpr static bool nothrow_copyable
228 = std::is_nothrow_copy_constructible<Value>::value;
229 constexpr static bool nothrow_steppable = noexcept(min + step);
230
231 public:
240 constexpr range_t(Value min_, Value max_, Delta step_ = 1)
241 : min(min_)
242 , max(max_)
243 , step(step_) {
244 normalize();
245 }
252 constexpr range_t(Value max_)
253 : range_t(Value{}, max_, (max_ >= Value{}) ? 1 : -1) {}
254
259 struct iterator {
260 Value val;
261 Delta step;
262
263 using difference_type = std::ptrdiff_t;
264 using value_type = Value;
265 using pointer = const Value*;
266 using reference = Value;
267 using iterator_category = std::input_iterator_tag;
268
274 constexpr auto operator*() const noexcept(nothrow_copyable) -> Value {
275 return val;
276 }
283 constexpr auto operator->() const noexcept -> pointer { return &val; }
289 constexpr auto operator++() & noexcept(nothrow_steppable) -> iterator& {
290 val = static_cast<Value>(val + step);
291 return *this;
292 }
299 constexpr auto operator++(int) noexcept(nothrow_steppable) -> iterator {
300 auto ret = *this;
301 val = val + step;
302 return ret;
303 }
310 constexpr friend auto operator==(iterator l, iterator r) noexcept
311 -> bool {
312 return l.val == r.val and l.step == r.step;
313 }
320 constexpr friend auto operator!=(iterator l, iterator r) noexcept
321 -> bool {
322 return l.val != r.val or l.step != r.step;
323 }
330 constexpr friend auto operator<(iterator l, iterator r) noexcept -> bool {
331 if (l.step > 0)
332 return l.val < r.val;
333 else
334 return l.val > r.val;
335 }
342 constexpr friend auto operator<=(iterator l, iterator r) noexcept
343 -> bool {
344 return not (r < l);
345 }
352 constexpr friend auto operator>(iterator l, iterator r) noexcept -> bool {
353 return r < l;
354 }
361 constexpr friend auto operator>=(iterator l, iterator r) noexcept
362 -> bool {
363 return not (l < r);
364 }
365 constexpr auto operator[](std::ptrdiff_t x) const noexcept -> Value {
366 return static_cast<Value>(val + x * step);
367 }
368 template <typename Integral>
369 constexpr auto operator[](Integral x) const noexcept -> Value {
370 return static_cast<Value>(val + std::ptrdiff_t(x) * step);
371 }
372 };
373
377 constexpr auto begin() const noexcept -> iterator { return {min, step}; }
381 constexpr auto end() const noexcept -> iterator { return {max, step}; }
382
386 constexpr auto size() const noexcept -> std::size_t {
387 return static_cast<std::size_t>(std::abs(max - min) / step);
388 }
389
393 friend constexpr auto begin(const range_t& r) noexcept -> iterator {
394 return {r.min, r.step};
395 }
399 friend constexpr auto end(const range_t& r) noexcept -> iterator {
400 return {r.max, r.step};
401 }
402
406 friend constexpr auto size(const range_t& r) noexcept -> std::size_t {
407 return (r.max - r.min) / r.step;
408 }
409
413 constexpr auto empty() const noexcept -> bool { return size() == 0; }
414
415 template <typename Integral>
416 constexpr auto operator[](Integral x) const noexcept
417 -> decltype(begin()[x]) {
418 return begin()[x];
419 }
420
421 constexpr auto lesser() const noexcept(nothrow_copyable) -> Value {
422 return (step > 0) ? max : min;
423 }
424
425 constexpr auto greater() const noexcept(nothrow_copyable) -> Value {
426 return (step > 0) ? min : max;
427 }
428
432 template <
433 typename Container,
435 is_linear_container_v<
436 Container> and std::is_constructible<Container, iterator, iterator>::value>* = nullptr>
437 explicit operator Container() const
438 noexcept(noexcept(Container(std::declval<iterator>(),
439 std::declval<iterator>()))) {
440 return Container(begin(), end());
441 }
442
446 template <
447 typename Container,
449 is_setlike_v<
450 Container> and std::is_constructible<Container, iterator, iterator>::value>* = nullptr>
451 explicit operator Container() const
452 noexcept(noexcept(Container(std::declval<iterator>(),
453 std::declval<iterator>()))) {
454 return Container(begin(), end());
455 }
456
462 constexpr friend auto operator==(range_t l, range_t r) noexcept -> bool {
463 return (l.empty() and r.empty())
464 or ((l.begin() == r.begin()) and (l.end() == r.end())
465 and (l.step == r.step));
466 }
472 constexpr friend auto operator!=(range_t l, range_t r) noexcept -> bool {
473 return not (l == r);
474 }
475
476 private:
477 template <typename T>
478 static constexpr enable_if_t<not std::is_signed<T>::value, std::true_type>
479 positive(const T&) {
480 return {};
481 }
482 template <typename T>
483 static constexpr enable_if_t<std::is_signed<T>::value, bool> positive(T v) {
484 return v >= 0;
485 }
486 template <typename R, typename T,
487 enable_if_t<std::is_integral<R>::value
488 and std::is_integral<T>::value>* = nullptr>
489 static constexpr auto signed_cast(T v) {
490 return kblib::signed_cast<R>(v);
491 }
492 template <typename R, typename T,
493 enable_if_t<not (std::is_integral<R>::value
494 and std::is_integral<T>::value)>* = nullptr>
495 static constexpr auto signed_cast(T v) {
496 return v;
497 }
498
499 constexpr auto normalize() noexcept(nothrow_steppable) -> void {
500 if (min == max) {
501 } else if (step == 0) {
503 max = min + 1;
504 } else {
505 max = min - 1;
506 }
507 } else {
508#pragma GCC diagnostic push
509#pragma GCC diagnostic ignored "-Wsign-conversion"
510#pragma GCC diagnostic ignored "-Wconversion"
511#pragma GCC diagnostic ignored "-Wsign-compare"
512#pragma GCC diagnostic ignored "-Wimplicit-int-conversion"
513#pragma GCC diagnostic ignored "-Wshorten-64-to-32"
514 auto difference = max - min;
515 std::ptrdiff_t sign = (step > 0) ? 1 : -1;
516 if ((sign * to_signed(difference)) <= (sign * step)) {
517 step = sign;
518 max = min + step;
519 } else {
520 auto remainder = difference % step;
521 if (remainder != 0) {
522 max = max - remainder;
523 assert(not (positive(max)
524 and (signed_cast<Delta>(
526 < step)));
527 max = max + step;
528 }
529 }
530#pragma GCC diagnostic pop
531 }
532 }
533};
534
535namespace detail_iterators {
536 template <typename T, typename U, typename = void>
537 struct is_addable : std::false_type {};
538
539 template <typename T, typename U>
540 struct is_addable<T, U,
541 void_t<decltype(std::declval<T&>() + std::declval<U&>())>>
542 : std::true_type {};
543} // namespace detail_iterators
544
545struct adjuster {
546 std::ptrdiff_t adj;
547 constexpr adjuster(std::ptrdiff_t adj_) noexcept
548 : adj(adj_) {}
549 constexpr operator std::ptrdiff_t() const noexcept { return adj; }
550};
551
552template <typename T>
553constexpr auto operator+(T val, adjuster a) noexcept
555 decltype(std::advance(val, a.adj))> {
556 return std::advance(val, a.adj);
557}
558
564 constexpr incrementer() noexcept = default;
565 constexpr incrementer(int) noexcept {}
566 constexpr operator int() const noexcept { return 1; }
567 friend constexpr auto operator*(std::ptrdiff_t x, incrementer) {
568 return adjuster{x};
569 }
570
571 template <typename T>
572 constexpr auto operator()(T& t) -> T& {
573 return ++t;
574 }
575};
576
580template <typename T>
581constexpr auto operator+(T val, incrementer) -> T {
582 return ++val;
583}
584
590 constexpr decrementer() noexcept = default;
591 constexpr decrementer(int) noexcept {}
592 constexpr operator int() const noexcept { return -1; }
593 friend constexpr auto operator*(std::ptrdiff_t x, decrementer) {
594 return adjuster{-x};
595 }
596 template <typename T>
597 constexpr auto operator()(T& t) -> T& {
598 return --t;
599 }
600};
601
605template <typename T>
606constexpr auto operator+(T val, decrementer) -> T {
607 return --val;
608}
609
620template <typename Value, typename Delta = int>
621constexpr auto range(Value min, Value max, Delta step = 0)
623 if (step == 0) {
624 if (min <= max) {
625 return {min, max, 1};
626 } else {
627 return {min, max, -1};
628 }
629 } else {
630 return {min, max, step};
631 }
632}
633
641template <typename Value>
642constexpr auto range(Value max) -> range_t<Value, incrementer> {
643 return {max};
644}
645
646#if KBLIB_USE_CXX17
647
648template <typename Value, typename Delta>
649class irange_t {
650 public:
651 Value min, max;
652 Delta step;
653
654 constexpr static bool nothrow_copyable
655 = std::is_nothrow_copy_constructible<Value>::value;
656 constexpr static bool nothrow_steppable = noexcept(min + step);
657};
658
659template <typename Value, typename Delta = int>
660constexpr auto irange(Value, Value, Delta = 0) {}
661
662template <typename T>
663class enumerator_iterator;
664
668namespace detail_enumerate {
669
670 template <typename T1, typename T2>
671 auto get_or(T1&& t1, T2&& t2) -> decltype(auto) {
672 return t1 ? *t1 : *t2;
673 }
674
675 struct force_copy_tag {};
676 // Get a pointer which is guaranteed to be invalid to use (but not UB to
677 // merely store)
678 template <typename T>
679 auto get_magic_ptr() -> T* {
680 static const char enumeration_magic_pointer = '\0';
681 return reinterpret_cast<T*>(
682 const_cast<char*>(&enumeration_magic_pointer));
683 }
684
685} // namespace detail_enumerate
686
687template <typename T>
689 public:
690 enumeration() = default;
691
693 : idx(other.idx)
694 , local([&] {
695 assert(other.source or other.local);
696 assert(other.source != detail_enumerate::get_magic_ptr<T>());
697 return other.copied();
698 }())
699 , source(nullptr) {}
700 enumeration(volatile enumeration& other)
701 : enumeration(const_cast<const enumeration&>(other)) {}
702
704 auto operator=(const enumeration&) = delete;
705 auto operator=(enumeration&&) = delete;
706
707 ~enumeration() = default;
708
709 private:
711 : idx(i) {}
712
713 public:
714 auto index() const noexcept -> std::size_t { return idx; }
715
716 auto copied() & noexcept -> std::remove_const_t<T>& {
717 assert(source != detail_enumerate::get_magic_ptr<T>());
718 assert(local);
719 return *local;
720 }
721 auto copied() const& noexcept -> const T& {
722 assert(source != detail_enumerate::get_magic_ptr<T>());
723 return detail_enumerate::get_or(local, source);
724 }
725
726 auto reffed() & noexcept -> T& {
727 assert(source != detail_enumerate::get_magic_ptr<T>());
728 return detail_enumerate::get_or(local, source);
729 }
730 auto reffed() const& noexcept -> const T& {
731 assert(source != detail_enumerate::get_magic_ptr<T>());
732 return detail_enumerate::get_or(local, source);
733 }
734
735 private:
736 auto set(T* t) & -> void { source = t; }
737
738 auto advance() & noexcept -> void {
739 ++idx;
740 source = detail_enumerate::get_magic_ptr<T>();
741 local = std::nullopt;
742 }
743
744 std::size_t idx = 0;
745 mutable std::optional<std::remove_const_t<T>> local = std::nullopt;
746 T* source = detail_enumerate::get_magic_ptr<T>();
747
748 template <typename>
750};
751} // namespace kblib
752
753namespace std {
754# if defined(__clang__)
755// Fix from: https://github.com/nlohmann/json/issues/1401
756# pragma clang diagnostic push
757# pragma clang diagnostic ignored "-Wmismatched-tags"
758# endif
759
760template <typename T>
761class tuple_size<::kblib::enumeration<T>>
762 : public std::integral_constant<std::size_t, 2> {};
763
764template <typename T>
765class tuple_element<0, ::kblib::enumeration<T>> {
766 public:
767 using type = std::size_t;
768};
769template <typename T>
770class tuple_element<0, volatile ::kblib::enumeration<T>> {
771 public:
772 using type = std::size_t;
773};
774template <typename T>
775class tuple_element<0, const volatile ::kblib::enumeration<T>> {
776 public:
777 using type = const std::size_t;
778};
779
783template <typename T>
784class tuple_element<1, volatile ::kblib::enumeration<T>> {
785 public:
786 using type = T;
787};
791template <typename T>
792class tuple_element<1, const volatile ::kblib::enumeration<T>> {
793 public:
794 using type = const T;
795};
799template <typename T>
800class tuple_element<1, ::kblib::enumeration<T>> {
801 public:
802 using type = std::remove_const_t<T>;
803};
807template <typename T>
808class tuple_element<1, const ::kblib::enumeration<T>> {
809 public:
810 using type = const T;
811};
812
813# if defined(__clang__)
814# pragma clang diagnostic pop
815# endif
816
817} // namespace std
818
819namespace KBLIB_NS {
820
821// When a structured binding is created by value, this function is called as if
822// by get<i>(std::move(e)), so it does not call the lvalue reference function.
823// I have no idea why it's implicitly moved, but it works for my purposes.
824template <std::size_t I, typename T>
825auto get(enumeration<T>&& e) -> decltype(auto) {
826 static_assert(I <= 1, "enumeration only has two elements");
827 if constexpr (I == 0) {
828 return e.index();
829 } else {
830 return e.copied();
831 }
832}
833template <std::size_t I, typename T>
834auto get(const enumeration<T>&& e) -> decltype(auto) {
835 static_assert(I <= 1, "enumeration only has two elements");
836 if constexpr (I == 0) {
837 return e.index();
838 } else {
839 return e.copied();
840 }
841}
842// When captured by reference, the volatile qualifier is added, which allows
843// std::tuple_element to detect the copying-nonconst-from-const case.
844template <std::size_t I, typename T>
845auto get(volatile enumeration<T>& e) -> decltype(auto) {
846 static_assert(I <= 1, "enumeration only has two elements");
847 if constexpr (I == 0) {
848 return const_cast<enumeration<T>&>(e).index();
849 } else {
850 return const_cast<enumeration<T>&>(e).reffed();
851 }
852}
853
854template <std::size_t I, typename T>
855auto get(const volatile enumeration<T>& e) -> decltype(auto) {
856 static_assert(I <= 1, "enumeration only has two elements");
857 if constexpr (I == 0) {
858 return const_cast<const enumeration<T>&>(e).index();
859 } else {
860 return const_cast<const enumeration<T>&>(e).reffed();
861 }
862}
863
864template <typename It>
866 public:
869 typename std::iterator_traits<It>::value_type>;
870
872 using difference_type = std::ptrdiff_t;
873 using pointer = const value_type*;
874 using reference = const value_type&;
875 using iterator_category = std::input_iterator_tag;
876
879 : enumerator_iterator(detail_enumerate::force_copy_tag{},
880 other.curr_.idx, other.it_) {}
882 : it_(it) {}
883
887
889
890 auto operator*() & -> volatile value_type& {
891 if (not captured) {
892 curr_.set(to_pointer(it_));
893 captured = true;
894 }
895 return curr_;
896 }
898 curr_.advance();
899 captured = false;
900 ++it_;
901 return *this;
902 }
903
904 friend auto operator==(const enumerator_iterator& lhs,
905 const enumerator_iterator& rhs) noexcept -> bool {
906 return lhs.it_ == rhs.it_;
907 }
908 friend auto operator!=(const enumerator_iterator& lhs,
909 const enumerator_iterator& rhs) noexcept -> bool {
910 return lhs.it_ != rhs.it_;
911 }
912
913 private:
915 It it)
916 : it_(it)
917 , curr_(t, idx) {}
918
919 It it_;
920 bool captured = false;
921 value_type curr_;
922};
923
924template <typename Range, typename = void>
925class enumerator_t;
926
927template <typename Range>
928class enumerator_t<Range, void> {
929 public:
931
932 using range_t = typename std::remove_reference_t<Range>;
933 using nested_iterator = decltype(r.begin());
934 using nested_end_iterator = decltype(r.end());
937
938 using nested_const_iterator = typename range_t::const_iterator;
940
941 auto begin() const& noexcept(noexcept(r.cbegin())) -> const_iterator {
942 return r.cbegin();
943 }
944 auto begin() & noexcept(noexcept(r.begin())) -> iterator {
945 return r.begin();
946 }
947
948 auto end() const& noexcept(noexcept(r.cend())) -> const_iterator {
949 return r.cend();
950 }
951 auto end() & noexcept(noexcept(r.end())) -> end_iterator { return r.end(); }
952};
953
954template <typename It, typename EndIt>
956 public:
957 using nested_iterator = It;
960
961 auto begin() const& noexcept -> iterator { return {r_begin}; }
962
963 auto end() const& noexcept -> end_iterator { return {r_end}; }
964
966 EndIt r_end;
967};
968
988template <typename It, typename EIt>
989auto magic_enumerate(It begin, EIt end) -> enumerator_t<It, EIt> {
990 return {begin, end};
991}
992
1013template <typename Range>
1014auto magic_enumerate(Range&& r) -> auto {
1015 if constexpr (std::is_lvalue_reference_v<Range&&>) {
1016 using std::begin;
1017 using std::end;
1018 return magic_enumerate(begin(r), end(r));
1019 } else {
1020 return enumerator_t<Range&&>{std::forward<Range>(r)};
1021 }
1022}
1023
1024#endif
1025
1029template <typename Iter1, typename Iter2>
1031 Iter1 begin_;
1032 Iter2 end_;
1033
1034 using value_type = decltype(*begin_);
1035
1036 constexpr auto begin() const noexcept -> Iter1 { return begin_; }
1037 constexpr auto end() const noexcept -> Iter2 { return end_; }
1038 constexpr auto rbegin() const noexcept -> auto {
1039 return std::make_reverse_iterator(begin_);
1040 }
1041 constexpr auto rend() const noexcept -> auto {
1042 return std::make_reverse_iterator(end_);
1043 }
1044
1045 constexpr friend auto begin(const indirect_range& r) noexcept -> Iter1 {
1046 return r.begin_;
1047 }
1048 constexpr friend auto end(const indirect_range& r) noexcept -> Iter2 {
1049 return r.end_;
1050 }
1051};
1052
1059template <typename Iter1, typename Iter2>
1060constexpr auto indirect(Iter1 begin, Iter2 end) noexcept(noexcept(
1061 indirect_range<Iter1, Iter2>{begin, end})) -> indirect_range<Iter1, Iter2> {
1062 return {begin, end};
1063}
1064
1065#if KBLIB_USE_CXX17
1066
1067template <typename Iter1, typename Iter2>
1069
1070template <typename Iter1, typename Iter2>
1071auto cry_enumerate(Iter1 begin, Iter2 end) -> auto {
1072 return cry_enumerate(indirect_range{begin, end});
1073}
1074
1075#endif
1076
1077// Fixed number of ranges
1078template <typename Iter1, typename EndIter = Iter1, std::size_t count = 0>
1080 public:
1081 private:
1082 struct range {
1083 Iter1 begin;
1084 EndIter end;
1085 };
1086
1087 std::array<range, count> ranges;
1088};
1089
1090// Dynamic number of ranges
1091template <typename Iter1, typename EndIter>
1092class multi_range<Iter1, EndIter, 0> {
1093 public:
1094 private:
1095 struct range {
1096 Iter1 begin;
1097 EndIter end;
1098 };
1099
1100 std::vector<range> ranges;
1101};
1102
1108template <typename T>
1113 constexpr auto operator*() noexcept -> T& { return val; }
1117 constexpr auto operator*() const noexcept -> const T& { return val; }
1118
1122 constexpr auto operator->() noexcept -> T* { return &val; }
1126 constexpr auto operator->() const noexcept -> const T* { return &val; }
1127
1131 constexpr auto get() noexcept -> T* { return &val; }
1135 constexpr auto get() const noexcept -> const T* { return &val; }
1136
1138};
1139
1140#if KBLIB_USE_CXX17
1141
1148template <typename base_iterator, typename operation>
1150 private:
1151 base_iterator it;
1152 operation op;
1153
1154 public:
1155 using difference_type = std::ptrdiff_t;
1156 using result_type = decltype(kblib::invoke(op, *it));
1158 = decltype(kblib::invoke(std::as_const(op), *std::as_const(it)));
1160 using pointer = void;
1162 using iterator_category = std::input_iterator_tag;
1163
1171 transform_iterator(base_iterator _it,
1172 operation _op) noexcept(noexcept(base_iterator{
1173 _it}) and noexcept(std::is_nothrow_move_constructible<operation>::value))
1174 : it(_it)
1175 , op(std::move(_op)) {}
1176
1182 transform_iterator(base_iterator end_it) noexcept(noexcept(base_iterator{
1183 end_it}))
1184 : it(end_it)
1185 , op() {}
1186
1192 auto operator*() noexcept(noexcept(kblib::invoke(op, *it)))
1193 -> decltype(auto) {
1194 return kblib::invoke(op, *it);
1195 }
1201 decltype(auto) operator*() const noexcept(noexcept(kblib::invoke(op, *it))) {
1202 return kblib::invoke(op, *it);
1203 }
1204
1209 auto operator->() noexcept(noexcept(kblib::invoke(op, *it))) -> auto {
1210 return containing_ptr<result_type>{{kblib::invoke(op, *it)}};
1211 }
1216 auto operator->() const noexcept(noexcept(kblib::invoke(op, *it))) -> auto {
1218 }
1219
1223 auto operator++() noexcept(noexcept(++it)) -> transform_iterator& {
1224 ++it;
1225 return *this;
1226 }
1227
1232 [[deprecated("Needlessly copies op. Use preincrement instead.")]] auto
1233 operator++(int) noexcept(noexcept(transform_iterator{it++, op}))
1235 return {it++, op};
1236 }
1237
1238 auto base() const noexcept -> base_iterator { return it; }
1239
1240 auto from_base(base_iterator it_) const
1241 noexcept(std::is_nothrow_copy_constructible_v<operation>)
1243 return {it_, op};
1244 }
1245
1249 friend auto operator==(const transform_iterator& lhs,
1250 const transform_iterator& rhs) noexcept -> bool {
1251 return lhs.it == rhs.it;
1252 }
1253
1257 friend auto operator!=(const transform_iterator& lhs,
1258 const transform_iterator& rhs) noexcept -> bool {
1259 return lhs.it != rhs.it;
1260 }
1261
1262 template <typename OIt>
1263 friend auto operator==(const transform_iterator& lhs,
1264 const OIt& rhs) noexcept -> bool {
1265 return lhs.base() == rhs;
1266 }
1267 template <typename OIt>
1268 friend auto operator==(const OIt& lhs,
1269 const transform_iterator& rhs) noexcept -> bool {
1270 return lhs == rhs.base();
1271 }
1272
1273 template <typename OIt>
1274 friend auto operator!=(const transform_iterator& lhs,
1275 const OIt& rhs) noexcept -> bool {
1276 return lhs.base() != rhs;
1277 }
1278 template <typename OIt>
1279 friend auto operator!=(const OIt& lhs,
1280 const transform_iterator& rhs) noexcept -> bool {
1281 return lhs != rhs.base();
1282 }
1283};
1284
1285template <typename It, typename operation>
1287
1297template <typename base_iterator, typename operation>
1298[[deprecated("use transformer instead")]] auto make_transform_iterator(
1299 base_iterator it,
1300 operation
1302 it, std::move(op)})) -> transform_iterator<base_iterator, operation> {
1303 return {it, std::move(op)};
1304}
1305
1313template <typename base_iterator, typename operation>
1314auto transformer(base_iterator it, operation op) noexcept(
1315 noexcept(transform_iterator<base_iterator, operation>{it, std::move(op)}))
1316 -> transform_iterator<base_iterator, operation> {
1317 return {it, std::move(op)};
1318}
1319
1320template <typename It, typename EndIt, typename operation>
1321auto transform_range(It begin, EndIt end, operation op) noexcept(
1322 noexcept(indirect(transform_iterator{begin, op}, end))) -> auto {
1323 return indirect(transform_iterator{begin, op}, end);
1324}
1325#endif
1326
1327template <typename InputIt1, typename EndIt, typename InputIt2>
1329 InputIt1 pos1{};
1330 EndIt end1{};
1331 InputIt2 pos2{};
1332
1333 constexpr static bool is_nothrow_copyable
1334 = std::is_nothrow_copy_constructible<InputIt1>::value
1335 and std::is_nothrow_copy_constructible<EndIt>::value
1336 and std::is_nothrow_copy_constructible<InputIt2>::value;
1337
1338 auto operator++() noexcept(noexcept(++pos1) and noexcept(++pos2))
1339 -> zip_iterator& {
1340 ++pos1;
1341 ++pos2;
1342 return *this;
1343 }
1344 auto operator++(int) noexcept(is_nothrow_copyable and noexcept(
1345 ++pos1) and noexcept(++pos2)) -> const zip_iterator {
1346 auto tmp = *this;
1347 ++pos1;
1348 ++pos2;
1349 return tmp;
1350 }
1351
1352 KBLIB_NODISCARD auto operator*() const noexcept -> auto {
1353 return std::forward_as_tuple(*pos1, *pos2);
1354 }
1355
1356 KBLIB_NODISCARD auto begin() const noexcept(is_nothrow_copyable)
1357 -> zip_iterator {
1358 return *this;
1359 }
1361 noexcept(std::is_nothrow_copy_constructible<EndIt>::value and
1362 std::is_nothrow_copy_constructible<InputIt2>::value)
1363 -> zip_iterator<EndIt, EndIt, InputIt2> {
1364 return {end1, end1};
1365 }
1366
1368 const zip_iterator& z1,
1369 const zip_iterator& z2) noexcept(noexcept(z1.pos1 == z2.pos1)) -> bool {
1370 return z1.pos1 == z2.pos1;
1371 }
1373 const zip_iterator& z1,
1374 const zip_iterator& z2) noexcept(noexcept(z1.pos1 != z2.pos1)) -> bool {
1375 return z1.pos1 != z2.pos1;
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 }
1385 const zip_iterator& z1,
1386 zip_iterator<EndIt, EndIt, InputIt2> end) noexcept(noexcept(z1.pos1
1387 == end.val))
1388 -> bool {
1389 return z1.end1 != end.val;
1390 }
1391};
1392
1393template <typename It1, typename It2>
1394struct zip_iterator<It1, It1, It2> {
1395 It1 pos1{};
1396 It1 end1{};
1397 It2 pos2{};
1398
1399 constexpr static bool is_nothrow_copyable
1400 = std::is_nothrow_copy_constructible<It1>::value
1401 and std::is_nothrow_copy_constructible<It2>::value;
1402
1403 auto operator++() noexcept(noexcept(++pos1)) -> zip_iterator& {
1404 ++pos1;
1405 ++pos2;
1406 return *this;
1407 }
1408 auto operator++(int) noexcept(is_nothrow_copyable and noexcept(++pos1))
1409 -> const zip_iterator {
1410 auto tmp = *this;
1411 ++pos1;
1412 ++pos2;
1413 return tmp;
1414 }
1415
1417 return std::forward_as_tuple(*pos1, *pos2);
1418 }
1419
1420 KBLIB_NODISCARD auto begin() const noexcept(is_nothrow_copyable)
1421 -> zip_iterator {
1422 return *this;
1423 }
1425 noexcept(std::is_nothrow_copy_constructible<It1>::value)
1426 -> zip_iterator {
1427 return {end1, end1, pos2};
1428 }
1429
1431 const zip_iterator& z1,
1432 const zip_iterator& z2) noexcept(noexcept(z1.pos1 == z2.pos1)) -> bool {
1433 return z1.pos1 == z2.pos1;
1434 }
1436 const zip_iterator& z1,
1437 const zip_iterator& z2) noexcept(noexcept(z1.pos1 == z2.pos1)) -> bool {
1438 return z1.pos1 != z2.pos1;
1439 }
1440};
1441
1453template <typename InputIt1, typename EndIt, typename InputIt2>
1454KBLIB_NODISCARD auto zip(InputIt1 begin1, EndIt end1, InputIt2 begin2) noexcept(
1457 return {begin1, end1, begin2};
1458}
1459
1469template <typename Range1, typename Range2>
1470KBLIB_NODISCARD auto zip(Range1&& r1, Range2&& r2) noexcept(
1471 zip_iterator<decltype(begin(r1)), decltype(end(r1)),
1472 decltype(begin(r2))>::is_nothrow_copyable)
1473 -> zip_iterator<decltype(begin(r1)), decltype(end(r1)),
1474 decltype(begin(r2))> {
1475 return {begin(r1), end(r1), begin(r2)};
1476}
1477
1479template <typename ForwardIt, typename EndIt>
1481 public:
1482 using difference_type = std::ptrdiff_t;
1483 using base_reference = typename std::iterator_traits<ForwardIt>::reference;
1484 using value_type = std::pair<base_reference, base_reference>;
1485 using pointer = void;
1487 using iterator_category = std::input_iterator_tag;
1488
1489 private:
1490 ForwardIt it;
1491};
1492
1499template <typename Container, typename F>
1501 public:
1508 explicit back_insert_iterator_F(Container& c, F f)
1509 : container(c)
1510 , fun(std::move(f)) {}
1511
1512 using value_type = void;
1513 using difference_type = void;
1514 using pointer = void;
1515 using reference = void;
1516 using iterator_category = std::output_iterator_tag;
1517
1518 template <typename V>
1526 auto operator=(V&& value) -> back_insert_iterator_F& {
1527 container.push_back(invoke(fun, std::forward<V>(value)));
1528 return *this;
1529 }
1530
1534 auto operator*() -> back_insert_iterator_F& { return *this; }
1538 auto operator++() -> back_insert_iterator_F& { return *this; }
1539
1540 private:
1541 Container& container;
1542 F fun;
1543};
1544
1549template <typename F>
1551 private:
1552 F fun;
1553
1554 public:
1555 using value_type = void;
1556 using difference_type = void;
1557 using pointer = void;
1558 using reference = void;
1559 using iterator_category = std::output_iterator_tag;
1560
1566 explicit consume_iterator(F f)
1567 : fun(std::move(f)) {}
1568
1571 auto operator=(const consume_iterator&) & -> consume_iterator& = default;
1574
1581 template <typename V>
1582 auto operator=(V&& value) noexcept(
1583 noexcept(kblib::invoke(fun, std::forward<V>(value))))
1586 kblib::invoke(fun, std::forward<V>(value));
1587 return *this;
1588 }
1589
1593 auto operator*() -> consume_iterator& { return *this; }
1597 auto operator++() -> consume_iterator& { return *this; }
1601 auto operator++(int) -> consume_iterator& { return *this; }
1602};
1603
1613template <typename F>
1615 return consume_iterator<F>{std::move(f)};
1616}
1617
1618} // namespace kblib
1619
1620#endif // KBLIB_ITERATORS_H
TODO(killerbee13): Implement adjacent_iterator.
Definition: iterators.h:1480
std::input_iterator_tag iterator_category
Definition: iterators.h:1487
std::ptrdiff_t difference_type
Definition: iterators.h:1482
std::pair< base_reference, base_reference > value_type
Definition: iterators.h:1484
typename std::iterator_traits< ForwardIt >::reference base_reference
Definition: iterators.h:1483
An OutputIterator that transforms the values assigned to it before inserting them into the back of a ...
Definition: iterators.h:1500
std::output_iterator_tag iterator_category
Definition: iterators.h:1516
auto operator*() -> back_insert_iterator_F &
A no-op.
Definition: iterators.h:1534
auto operator=(V &&value) -> back_insert_iterator_F &
Calls container.push_back(kblib::invoke(fun, std::forward<V>(value)));.
Definition: iterators.h:1526
back_insert_iterator_F(Container &c, F f)
Definition: iterators.h:1508
auto operator++() -> back_insert_iterator_F &
A no-op.
Definition: iterators.h:1538
An OutputIterator that simply calls a provided functor for each value assigned to it.
Definition: iterators.h:1550
consume_iterator(const consume_iterator &)=default
std::output_iterator_tag iterator_category
Definition: iterators.h:1559
auto operator=(const consume_iterator &) &-> consume_iterator &=default
consume_iterator(F f)
Constructs a consume_iterator with the given function object.
Definition: iterators.h:1566
auto operator=(V &&value) noexcept(noexcept(kblib::invoke(fun, std::forward< V >(value)))) -> kblib::ignore_t< decltype(kblib::invoke(fun, std::forward< V >(value))), consume_iterator & >
Pass value to F.
Definition: iterators.h:1582
auto operator++(int) -> consume_iterator &
A no-op.
Definition: iterators.h:1601
consume_iterator(consume_iterator &&)=default
auto operator++() -> consume_iterator &
A no-op.
Definition: iterators.h:1597
auto operator=(consume_iterator &&) &-> consume_iterator &=default
auto operator*() -> consume_iterator &
A no-op.
Definition: iterators.h:1593
Like a std::back_insert_iterator, but it keeps track of how many insertions it has made,...
Definition: iterators.h:107
friend auto operator>=(const counting_back_insert_iterator &a, const counting_back_insert_iterator &b) noexcept -> bool
Definition: iterators.h:185
friend auto operator==(const counting_back_insert_iterator &a, const counting_back_insert_iterator &b) noexcept -> bool
Definition: iterators.h:160
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:190
friend auto operator<(const counting_back_insert_iterator &a, const counting_back_insert_iterator &b) noexcept -> bool
Definition: iterators.h:170
friend auto operator>(const counting_back_insert_iterator &a, const counting_back_insert_iterator &b) noexcept -> bool
Definition: iterators.h:180
auto operator++() &noexcept -> counting_back_insert_iterator &
Definition: iterators.h:152
friend auto operator!=(const counting_back_insert_iterator &a, const counting_back_insert_iterator &b) noexcept -> bool
Definition: iterators.h:165
counting_back_insert_iterator() noexcept=default
auto operator*() noexcept -> proxy_iterator
Definition: iterators.h:147
counting_back_insert_iterator(std::size_t n)
Definition: iterators.h:119
std::output_iterator_tag iterator_category
Definition: iterators.h:113
friend auto operator<=(const counting_back_insert_iterator &a, const counting_back_insert_iterator &b) noexcept -> bool
Definition: iterators.h:175
auto operator=(const enumeration &)=delete
auto copied() &noexcept -> std::remove_const_t< T > &
Definition: iterators.h:716
auto operator=(enumeration &&)=delete
auto reffed() &noexcept -> T &
Definition: iterators.h:726
auto index() const noexcept -> std::size_t
Definition: iterators.h:714
enumeration(volatile enumeration &other)
Definition: iterators.h:700
auto copied() const &noexcept -> const T &
Definition: iterators.h:721
auto reffed() const &noexcept -> const T &
Definition: iterators.h:730
~enumeration()=default
enumeration(const enumeration &other)
Definition: iterators.h:692
enumeration()=default
enumeration(enumeration &&)=delete
enumerator_iterator(const enumerator_iterator &other)
Definition: iterators.h:878
auto operator++() &-> enumerator_iterator &
Definition: iterators.h:897
auto operator=(enumerator_iterator &&) -> enumerator_iterator &=default
friend auto operator==(const enumerator_iterator &lhs, const enumerator_iterator &rhs) noexcept -> bool
Definition: iterators.h:904
std::input_iterator_tag iterator_category
Definition: iterators.h:875
auto operator=(const enumerator_iterator &) -> enumerator_iterator &=default
std::ptrdiff_t difference_type
Definition: iterators.h:872
copy_const_t< decltype(*std::declval< It & >()), typename std::iterator_traits< It >::value_type > nested_value
Definition: iterators.h:869
auto operator*() &-> volatile value_type &
Definition: iterators.h:890
enumerator_iterator(enumerator_iterator &&)=default
friend auto operator!=(const enumerator_iterator &lhs, const enumerator_iterator &rhs) noexcept -> bool
Definition: iterators.h:908
typename range_t::const_iterator nested_const_iterator
Definition: iterators.h:938
auto end() &noexcept(noexcept(r.end())) -> end_iterator
Definition: iterators.h:951
typename std::remove_reference_t< Range > range_t
Definition: iterators.h:932
decltype(r.begin()) nested_iterator
Definition: iterators.h:933
auto begin() const &noexcept(noexcept(r.cbegin())) -> const_iterator
Definition: iterators.h:941
auto begin() &noexcept(noexcept(r.begin())) -> iterator
Definition: iterators.h:944
decltype(r.end()) nested_end_iterator
Definition: iterators.h:934
detail::no_dangle_t< Range > r
Definition: iterators.h:930
auto end() const &noexcept(noexcept(r.cend())) -> const_iterator
Definition: iterators.h:948
auto end() const &noexcept -> end_iterator
Definition: iterators.h:963
auto begin() const &noexcept -> iterator
Definition: iterators.h:961
A range generator, similar to Python 3's range().
Definition: iterators.h:222
friend constexpr auto size(const range_t &r) noexcept -> std::size_t
Returns the distance between start() and stop().
Definition: iterators.h:406
constexpr auto operator[](Integral x) const noexcept -> decltype(begin()[x])
Definition: iterators.h:416
friend constexpr auto begin(const range_t &r) noexcept -> iterator
Returns an iterator to the beginning of the range.
Definition: iterators.h:393
constexpr auto lesser() const noexcept(nothrow_copyable) -> Value
Definition: iterators.h:421
constexpr auto end() const noexcept -> iterator
Return an iterator to the end of the range.
Definition: iterators.h:381
friend constexpr auto end(const range_t &r) noexcept -> iterator
Return an iterator to the end of the range.
Definition: iterators.h:399
constexpr auto empty() const noexcept -> bool
Query whether the range will generate any elements.
Definition: iterators.h:413
constexpr auto greater() const noexcept(nothrow_copyable) -> Value
Definition: iterators.h:425
constexpr auto size() const noexcept -> std::size_t
Returns the distance between start() and stop().
Definition: iterators.h:386
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:252
constexpr friend auto operator==(range_t l, range_t r) noexcept -> bool
Compare l and r for equality.
Definition: iterators.h:462
constexpr friend auto operator!=(range_t l, range_t r) noexcept -> bool
Compare l and r for inequality.
Definition: iterators.h:472
constexpr auto begin() const noexcept -> iterator
Returns an iterator to the beginning of the range.
Definition: iterators.h:377
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:240
An InputIterator that applies a transformation to the elements of the range.
Definition: iterators.h:1149
std::ptrdiff_t difference_type
Definition: iterators.h:1155
decltype(kblib::invoke(std::as_const(op), *std::as_const(it))) const_result_type
Definition: iterators.h:1158
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:1216
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:1171
friend auto operator==(const OIt &lhs, const transform_iterator &rhs) noexcept -> bool
Definition: iterators.h:1268
transform_iterator(base_iterator end_it) noexcept(noexcept(base_iterator{ end_it}))
constructs a non-dereferenceable sentinel iterator
Definition: iterators.h:1182
friend auto operator==(const transform_iterator &lhs, const OIt &rhs) noexcept -> bool
Definition: iterators.h:1263
auto operator++() noexcept(noexcept(++it)) -> transform_iterator &
Increments the underlying iterator and returns *this.
Definition: iterators.h:1223
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:1209
friend auto operator!=(const OIt &lhs, const transform_iterator &rhs) noexcept -> bool
Definition: iterators.h:1279
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:1233
decltype(kblib::invoke(op, *it)) result_type
Definition: iterators.h:1156
std::input_iterator_tag iterator_category
Definition: iterators.h:1162
auto operator*() noexcept(noexcept(kblib::invoke(op, *it))) -> decltype(auto)
Transforms the value obtained by dereferencing it.
Definition: iterators.h:1192
friend auto operator==(const transform_iterator &lhs, const transform_iterator &rhs) noexcept -> bool
Compares the base iterators of lhs and rhs.
Definition: iterators.h:1249
auto base() const noexcept -> base_iterator
Definition: iterators.h:1238
friend auto operator!=(const transform_iterator &lhs, const OIt &rhs) noexcept -> bool
Definition: iterators.h:1274
friend auto operator!=(const transform_iterator &lhs, const transform_iterator &rhs) noexcept -> bool
Compares the base iterators of lhs and rhs.
Definition: iterators.h:1257
auto from_base(base_iterator it_) const noexcept(std::is_nothrow_copy_constructible_v< operation >) -> transform_iterator
Definition: iterators.h:1240
This header provides some features of C++17 <type_traits> and other headers for C++14,...
auto get_magic_ptr() -> T *
Definition: iterators.h:679
auto get_or(T1 &&t1, T2 &&t2) -> decltype(auto)
Definition: iterators.h:671
typename no_dangle< T >::type no_dangle_t
Definition: tdecl.h:191
typename make_void< Ts... >::type void_t
Definition: fakestd.h:179
constexpr auto size(const C &c) -> decltype(c.size())
Definition: fakestd.h:366
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 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:1314
auto transform_range(It begin, EndIt end, operation op) noexcept(noexcept(indirect(transform_iterator{begin, op}, end))) -> auto
Definition: iterators.h:1321
auto consumer(F f) -> consume_iterator< F >
Creates a consume_iterator of deduced type F.
Definition: iterators.h:1614
constexpr auto to_signed(I x) -> std::make_signed_t< I >
Cast integral argument to corresponding signed type.
Definition: fakestd.h:593
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:72
constexpr auto a(const std::initializer_list< T > &a) -> auto
Index an array literal without naming its type.
Definition: simple.h:255
auto get(const volatile enumeration< T > &e) -> decltype(auto)
Definition: iterators.h:855
typename std::enable_if< B, T >::type enable_if_t
Definition: fakestd.h:54
typename ignore< U, T >::type ignore_t
An alias for ignore<U, T>::type.
Definition: traits.h:169
counting_back_insert_iterator< C > counting_back_inserter(C &c, std::size_t count=0)
Definition: iterators.h:203
constexpr auto e() -> T
Definition: stats.h:468
auto magic_enumerate(Range &&r) -> auto
Allow access to indexes while using range-based for loops. Safe to use with rvalues.
Definition: iterators.h:1014
constexpr auto irange(Value, Value, Delta=0)
Definition: iterators.h:660
auto cry_enumerate(Iter1 begin, Iter2 end) -> auto
Definition: iterators.h:1071
auto max_element(Container &c, Comp comp) -> value_type_linear_t< Container > *
Definition: iterators.h:78
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:1060
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:131
transform_iterator(It, operation) -> transform_iterator< It, operation >
constexpr auto operator+(T val, decrementer) -> T
Decrements val.
Definition: iterators.h:606
typename value_type_linear< Container >::type value_type_linear_t
Definition: fakestd.h:934
constexpr auto range(Value max) -> range_t< Value, incrementer >
Constructs a half-open range [0, max). The step is automatically determined based on the sign of max.
Definition: iterators.h:642
constexpr auto signed_cast(F x) -> enable_if_t< std::is_integral< A >::value and std::is_integral< F >::value and std::is_signed< A >::value, std::make_signed_t< F > >
Cast argument to equivalently-sized type with the same signednessas the template parameter.
Definition: fakestd.h:602
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:1298
auto zip(Range1 &&r1, Range2 &&r2) noexcept(zip_iterator< decltype(begin(r1)), decltype(end(r1)), decltype(begin(r2))>::is_nothrow_copyable) -> zip_iterator< decltype(begin(r1)), decltype(end(r1)), decltype(begin(r2))>
Iterate over two ranges in lockstep, like Python's zip.
Definition: iterators.h:1470
typename copy_const< C, V >::type copy_const_t
Definition: fakestd.h:871
Definition: bits.h:721
constexpr adjuster(std::ptrdiff_t adj_) noexcept
Definition: iterators.h:547
std::ptrdiff_t adj
Definition: iterators.h:546
A smart pointer to an object contained inside the smart pointer object.
Definition: iterators.h:1109
constexpr auto operator*() const noexcept -> const T &
Returns the contained object.
Definition: iterators.h:1117
constexpr auto operator->() const noexcept -> const T *
Return the address of the contained object.
Definition: iterators.h:1126
constexpr auto operator->() noexcept -> T *
Return the address of the contained object.
Definition: iterators.h:1122
constexpr auto get() noexcept -> T *
Returns the address of the contained object.
Definition: iterators.h:1131
constexpr auto operator*() noexcept -> T &
Returns the contained object.
Definition: iterators.h:1113
constexpr auto get() const noexcept -> const T *
Returns the address of the contained object.
Definition: iterators.h:1135
auto operator=(value_type &&value) &-> proxy_iterator &
Definition: iterators.h:134
auto operator=(const value_type &value) &-> proxy_iterator &
Definition: iterators.h:125
typename Container::value_type value_type
Definition: iterators.h:123
A struct which decrements anything it is added to. Suitable for use as a Delta type for range_t.
Definition: iterators.h:589
friend constexpr auto operator*(std::ptrdiff_t x, decrementer)
Definition: iterators.h:593
constexpr decrementer() noexcept=default
constexpr auto operator()(T &t) -> T &
Definition: iterators.h:597
A struct which increments anything it is added to. Suitable for use as a Delta type for range_t.
Definition: iterators.h:563
constexpr incrementer() noexcept=default
constexpr auto operator()(T &t) -> T &
Definition: iterators.h:572
friend constexpr auto operator*(std::ptrdiff_t x, incrementer)
Definition: iterators.h:567
Allow range-for iteration of an iterator pair.
Definition: iterators.h:1030
constexpr auto rend() const noexcept -> auto
Definition: iterators.h:1041
constexpr friend auto begin(const indirect_range &r) noexcept -> Iter1
Definition: iterators.h:1045
decltype(*begin_) value_type
Definition: iterators.h:1034
constexpr friend auto end(const indirect_range &r) noexcept -> Iter2
Definition: iterators.h:1048
constexpr auto begin() const noexcept -> Iter1
Definition: iterators.h:1036
constexpr auto end() const noexcept -> Iter2
Definition: iterators.h:1037
constexpr auto rbegin() const noexcept -> auto
Definition: iterators.h:1038
Determine if T is a valid output iterator to which values of type E may be written.
Definition: iterators.h:91
A helper struct which acts as an iterator for the range elements, as they are generated on the fly.
Definition: iterators.h:259
constexpr friend auto operator>(iterator l, iterator r) noexcept -> bool
Compare two range iterators.
Definition: iterators.h:352
constexpr auto operator[](Integral x) const noexcept -> Value
Definition: iterators.h:369
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:299
constexpr friend auto operator!=(iterator l, iterator r) noexcept -> bool
Compare two range iterators for inequality.
Definition: iterators.h:320
constexpr friend auto operator<(iterator l, iterator r) noexcept -> bool
Compare two range iterators.
Definition: iterators.h:330
constexpr auto operator*() const noexcept(nothrow_copyable) -> Value
Return the "pointed-to" value.
Definition: iterators.h:274
constexpr friend auto operator>=(iterator l, iterator r) noexcept -> bool
Compare two range iterators.
Definition: iterators.h:361
const Value * pointer
Definition: iterators.h:265
constexpr auto operator[](std::ptrdiff_t x) const noexcept -> Value
Definition: iterators.h:365
constexpr friend auto operator<=(iterator l, iterator r) noexcept -> bool
Compare two range iterators.
Definition: iterators.h:342
std::ptrdiff_t difference_type
Definition: iterators.h:263
constexpr auto operator++() &noexcept(nothrow_steppable) -> iterator &
Prefix increment. Advance to the next value in the range.
Definition: iterators.h:289
constexpr auto operator->() const noexcept -> pointer
Return a pointer to the value.
Definition: iterators.h:283
constexpr friend auto operator==(iterator l, iterator r) noexcept -> bool
Compare two range iterators for equality.
Definition: iterators.h:310
std::input_iterator_tag iterator_category
Definition: iterators.h:267
constexpr auto operator()(T *p) const noexcept -> T *
Definition: iterators.h:62
constexpr auto operator()(const ptr &p) const noexcept -> auto
Definition: iterators.h:55
constexpr auto operator()(ptr &&p) const noexcept -> auto
Definition: iterators.h:52
auto operator++() noexcept(noexcept(++pos1)) -> zip_iterator &
Definition: iterators.h:1403
friend auto operator!=(const zip_iterator &z1, const zip_iterator &z2) noexcept(noexcept(z1.pos1==z2.pos1)) -> bool
Definition: iterators.h:1435
friend auto operator==(const zip_iterator &z1, const zip_iterator &z2) noexcept(noexcept(z1.pos1==z2.pos1)) -> bool
Definition: iterators.h:1430
auto begin() const noexcept(is_nothrow_copyable) -> zip_iterator
Definition: iterators.h:1420
auto operator++(int) noexcept(is_nothrow_copyable and noexcept(++pos1)) -> const zip_iterator
Definition: iterators.h:1408
auto end() const noexcept(std::is_nothrow_copy_constructible< It1 >::value) -> zip_iterator
Definition: iterators.h:1424
auto operator++() noexcept(noexcept(++pos1) and noexcept(++pos2)) -> zip_iterator &
Definition: iterators.h:1338
friend auto operator==(const zip_iterator &z1, const zip_iterator &z2) noexcept(noexcept(z1.pos1==z2.pos1)) -> bool
Definition: iterators.h:1367
friend auto operator!=(const zip_iterator &z1, zip_iterator< EndIt, EndIt, InputIt2 > end) noexcept(noexcept(z1.pos1==end.val)) -> bool
Definition: iterators.h:1384
friend auto operator!=(const zip_iterator &z1, const zip_iterator &z2) noexcept(noexcept(z1.pos1 !=z2.pos1)) -> bool
Definition: iterators.h:1372
friend auto operator==(const zip_iterator &z1, zip_iterator< EndIt, EndIt, InputIt2 > end) noexcept(noexcept(z1.pos1==end.val)) -> bool
Definition: iterators.h:1377
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:1360
auto begin() const noexcept(is_nothrow_copyable) -> zip_iterator
Definition: iterators.h:1356
auto operator*() const noexcept -> auto
Definition: iterators.h:1352
auto operator++(int) noexcept(is_nothrow_copyable and noexcept(++pos1) and noexcept(++pos2)) -> const zip_iterator
Definition: iterators.h:1344
#define KBLIB_NS
Definition: tdecl.h:113
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Definition: tdecl.h:129
Contains some type traits not in the standard library that are useful in the implementation of kblib.