kblib 0.2.3
General utilities library for modern C++
enumerate-contrib-cry.h
Go to the documentation of this file.
1/* *****************************************************************************
2 * Copyright (c) 2020 Krystian Stasiowski
3 *
4 * This code adapted from code written by Krystian Stasiowski
5 * <sdkrystian@gmail.com>
6 *
7 * No specific license provisions were given, however permission was granted for
8 * me to include it in kblib.
9 *
10 * His code is much faster and cleaner than my magic_enumerate is. HOWEVER, it
11 * is fundamentally unable to detect the copying-nonconst-from-const case.
12 *
13 * My modifications are:
14 * - Change from [val, idx] to [idx, val] to match Python's enumerate()
15 * - Wrote documentation
16 * - Change name from value_and_index() to cry_enumerate()
17 * - Silenced Clang warnings about std::tuple_element specializations with
18 * mismatched tags.
19 * - Formatting
20 *
21 * All credit for everything else goes to Krystian.
22 *
23 * ****************************************************************************/
24
25#ifndef ENUMERATECONTRIB_H
26#define ENUMERATECONTRIB_H
27#include "tdecl.h"
28
29#include <iterator>
30#include <type_traits>
31
32#if KBLIB_USE_CXX17
33
34namespace KBLIB_NS {
38namespace detail_cry {
39 template <typename>
40 struct value_index_pair;
41
42 template <std::size_t N, typename T, std::enable_if_t<N == 0>* = nullptr>
43 auto get(T&& t)
44 -> std::conditional_t<std::is_reference_v<T>, const std::size_t&,
45 const std::size_t> {
46 return t.index;
47 }
48
49 template <std::size_t N, typename T, std::enable_if_t<N == 1>* = nullptr>
50 auto get(T&& t)
51 -> std::conditional_t<std::is_reference_v<T>,
52 typename std::remove_reference_t<T>::value_type&,
53 typename std::remove_reference_t<T>::value_type> {
54 // static_assert(std::is_reference_v<T>);
55 // static_assert(
56 // std::is_const_v<std::remove_reference_t<decltype(*t.iter)>>);
57 return *t.iter;
58 }
59
60 template <typename Iterator>
63 = std::remove_reference_t<decltype(*std::declval<Iterator&>())>;
64
65 std::size_t index;
66 Iterator iter;
67 };
68
69 template <typename Range, typename = void>
71 public:
72 using iterator_type = decltype(std::begin(std::declval<Range&>()));
73
75 : range_begin_(std::begin(range))
76 , range_end_(std::end(range)) {}
77
78 auto range_begin() -> iterator_type { return range_begin_; }
79
80 auto range_end() -> iterator_type { return range_end_; }
81
84 };
85
86 template <typename Range>
88 Range, std::enable_if_t<not std::is_reference_v<Range>>> {
89 public:
90 using iterator_type = decltype(std::begin(std::declval<Range&>()));
91
93 : range_(std::move(range)) {}
94
95 auto range_begin() -> iterator_type { return std::begin(range_); }
96
97 auto range_end() -> iterator_type { return std::end(range_); }
98
99 Range range_;
100 };
101
102 template <typename Range>
105
108 , begin_(this->range_begin(), 0)
109 , end_(this->range_end(), 0) {}
110
111 struct iterator {
112 private:
114
115 public:
116 iterator(iterator_type iter, std::size_t index = 0)
117 : pair_{index, iter} {}
118
119 auto operator*() -> value_index_pair<iterator_type>& { return pair_; }
120
121 auto operator++(int) -> iterator {
122 iterator copy(pair_.iter, pair_.index);
123 ++pair_.iter, ++pair_.index;
124 return copy;
125 }
126
127 auto operator++() -> iterator& {
128 ++pair_.iter, ++pair_.index;
129 return *this;
130 }
131
132 auto operator==(const iterator& other) const -> bool {
133 return other.pair_.iter == pair_.iter;
134 }
135
136 auto operator!=(const iterator& other) const -> bool {
137 return not (other == *this);
138 }
139 };
140
141 auto begin() -> iterator { return begin_; }
142
143 auto end() -> iterator { return end_; }
144
145 private:
146 iterator begin_;
147 iterator end_;
148 };
149} // namespace detail_cry
150} // namespace KBLIB_NS
151namespace std {
152# if defined(__clang__)
153// Fix from: https://github.com/nlohmann/json/issues/1401
154# pragma clang diagnostic push
155# pragma clang diagnostic ignored "-Wmismatched-tags"
156# endif
157template <typename T>
158struct tuple_size<kblib::detail_cry::value_index_pair<T>> {
159 static constexpr std::size_t value = 2;
160};
161
162template <typename T>
163struct tuple_element<0, kblib::detail_cry::value_index_pair<T>> {
164 using type = const std::size_t;
165};
166
167template <typename T>
168struct tuple_element<1, kblib::detail_cry::value_index_pair<T>> {
169 using type = std::remove_reference_t<decltype(*std::declval<T&>())>;
170};
171
172# if defined(__clang__)
173# pragma clang diagnostic pop
174# endif
175} // namespace std
176
177namespace KBLIB_NS {
178
185template <typename Range>
186auto cry_enumerate(Range&& range) -> auto {
188}
189
190} // namespace KBLIB_NS
191
192#endif
193
194#endif // ENUMERATECONTRIB_H
auto get(T &&t) -> std::conditional_t< std::is_reference_v< T >, const std::size_t &, const std::size_t >
The main namespace in which all entities from kblib are defined.
Definition: algorithm.h:44
typename std::enable_if< B, T >::type enable_if_t
Definition: fakestd.h:61
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:621
constexpr auto copy(InputIt first, EndIt last, OutputIt out) -> OutputIt
Copies all elements of [first, last) to out. It also allows for a sentinel end iterator.
Definition: algorithm.h:1322
Definition: bits.h:721
decltype(std::begin(std::declval< Range & >())) iterator_type
iterator(iterator_type iter, std::size_t index=0)
auto operator==(const iterator &other) const -> bool
auto operator!=(const iterator &other) const -> bool
auto operator*() -> value_index_pair< iterator_type > &
typename value_and_index_base< Range >::iterator_type iterator_type
std::remove_reference_t< decltype(*std::declval< Iterator & >())> value_type
std::remove_reference_t< decltype(*std::declval< T & >())> type
Provides macros and basic templates used by the rest of kblib.
#define KBLIB_NS
Definition: tdecl.h:113