libhatchet
Loading...
Searching...
No Matches
hxrange.hpp
Go to the documentation of this file.
1#pragma once
2// SPDX-FileCopyrightText: © 2017-2026 Adrian Johnston.
3// SPDX-License-Identifier: MIT
4// This file is licensed under the MIT license found in the LICENSE.md file.
5
17
18#include "libhatchet.h"
19
20// HX_USE_MACROS_WITH_MODULE allows including macros alongside the module.
21#if HX_USE_MACROS_WITH_MODULE
22#error Header does not provide macros alone.
23#endif
24
25#include "hxkey.hpp"
26
27HX_NS_BEGIN_
28
29#if HX_CPLUSPLUS >= 202002L
30
32// These are much simpler than the standard.
33template<typename T_>
34concept hxforward_iterator_concept_ = requires(T_& x_, const T_& y_) {
35 *x_;
36 { ++x_ } -> hxsame_as<T_&>;
37 { x_++ } -> hxsame_as<T_>;
38 { x_ == y_ } -> hxconvertible_to<bool>;
39 { x_ != y_ } -> hxconvertible_to<bool>;
40};
41template<typename T_>
42concept hxbidirectional_iterator_concept_ = hxforward_iterator_concept_<T_> && requires(T_& x_) {
43 { --x_ } -> hxsame_as<T_&>;
44 { x_-- } -> hxsame_as<T_>;
45};
46template<typename T_>
47concept hxrandom_iterator_concept_ = hxbidirectional_iterator_concept_<T_> && requires(
48 const T_& x_, const T_& y_, ptrdiff_t n_) {
49 { x_ + n_ } -> hxsame_as<T_>;
50 { x_ - n_ } -> hxsame_as<T_>;
51 { x_ - y_ } -> hxsame_as<ptrdiff_t>;
52 { x_ < y_ } -> hxconvertible_to<bool>;
53};
54template<typename T_>
55concept hxsorted_iterator_concept_ = hxrandom_iterator_concept_<T_> && requires(const T_& x_) {
56 { x_ < x_ } -> hxconvertible_to<bool>;
57 { x_ == x_ } -> hxconvertible_to<bool>;
58};
59template<typename T_>
60concept hxrange_concept_ = requires(T_& x_) {
61 { x_.begin() } -> hxforward_iterator_concept_;
62 { x_.end() } -> hxforward_iterator_concept_;
63};
64template<typename T_>
65concept hxrandom_range_concept_ = requires(T_& x_) {
66 { x_.begin() } -> hxrandom_iterator_concept_;
67 { x_.end() } -> hxrandom_iterator_concept_;
68};
69template<typename T_>
70concept hxsorted_range_concept_ = requires(T_& x_) {
71 { x_.begin() } -> hxsorted_iterator_concept_;
72 { x_.end() } -> hxsorted_iterator_concept_;
73};
75#else
76#define hxforward_iterator_concept_ typename
77#define hxbidirectional_iterator_concept_ typename
78#define hxrandom_iterator_concept_ typename
79#define hxrange_concept_ typename
80#define hxrandom_range_concept_ typename
81#define hxsorted_iterator_concept_ typename
82#define hxsorted_range_concept_ typename
83#endif
84
85// Forward declaration.
86template<hxrandom_range_concept_ range_t_, typename value_t_, typename less_t_> hxconstexpr
87auto hxlower_bound(range_t_&& range_, const value_t_& value_, const less_t_& less_)
88 -> decltype(range_.begin());
89
93template<typename iterator_t_>
94class hxrange {
95public:
98 template<typename T_, size_t N_>
99 hxinline hxconstexpr hxrange(T_ (&array_)[N_])
100 : m_begin_(+array_), m_end_(array_ + N_) { }
101
105 hxinline hxconstexpr hxrange(iterator_t_ begin_, iterator_t_ end_)
106 : m_begin_(begin_), m_end_(end_) { }
107
111 hxinline hxconstexpr hxrange(iterator_t_ begin_, hxsize_t size_)
112 : m_begin_(begin_), m_end_(begin_ + size_) { }
113
117 hxinline hxconstexpr hxrange(iterator_t_ begin_, size_t size_)
118 : m_begin_(begin_), m_end_(begin_ + size_) { }
119
122 iterator_t_ begin(void) const { return m_begin_; }
123
126 iterator_t_ end(void) const { return m_end_; }
127
128private:
129 iterator_t_ m_begin_;
130 iterator_t_ m_end_;
131};
132
137template<typename iterator_t_>
139hxrange<iterator_t_> hxmake_range(iterator_t_ begin_, iterator_t_ end_) {
140 return hxrange<iterator_t_>(begin_, end_);
141}
142
143template<typename T_, size_t N_>
145hxrange<T_*> hxmake_range(T_(&array_)[N_]) { return hxrange<T_*>(+array_, array_ + N_); }
146
150template<hxrange_concept_ range_t_, typename callable_t_>
152bool hxall_of(range_t_&& range_, callable_t_&& callable_) {
153 hxrestrict_t<decltype(range_.begin())> it_(range_.begin());
154 for(const auto end_ = range_.end(); it_ != end_; ++it_) {
155 if(!hxforward<callable_t_>(callable_)(*it_)) {
156 return false;
157 }
158 }
159 return true;
160}
161
165template<hxrange_concept_ range_t_, typename callable_t_>
167bool hxany_of(range_t_&& range_, callable_t_&& callable_) {
168 hxrestrict_t<decltype(range_.begin())> it_(range_.begin());
169 for(const auto end_ = range_.end(); it_ != end_; ++it_) {
170 if(hxforward<callable_t_>(callable_)(*it_)) {
171 return true;
172 }
173 }
174 return false;
175}
176
182template<hxrandom_iterator_concept_ iterator_t_, typename value_t_, typename less_t_>
184iterator_t_ hxbinary_search(iterator_t_ begin_, iterator_t_ end_, const value_t_& value_,
185 const less_t_& less_) {
186 const hxrestrict_t<iterator_t_> it_ = hxlower_bound(hxmake_range(begin_, end_), value_, less_);
187 return (it_ != end_ && !less_(value_, *it_)) ? it_ : end_;
188}
189
192template<hxrandom_range_concept_ range_t_, typename value_t_, typename less_t_>
194auto hxbinary_search(range_t_&& range_, const value_t_& value_, const less_t_& less_)
195 -> decltype(range_.begin()) {
196 const auto end_ = range_.end();
197 const hxrestrict_t<decltype(end_)> it_ = hxlower_bound(hxforward<range_t_>(range_), value_, less_);
198 return (it_ != end_ && !less_(value_, *it_)) ? it_ : end_;
199}
200
204template<hxsorted_range_concept_ range_t_, typename value_t_>
206auto hxbinary_search(range_t_&& range_, const value_t_& value_) -> decltype(range_.begin()) {
207 using less_t_ = hxkey_less_t<decltype(*range_.begin())>;
208 const auto end_ = range_.end();
209 const hxrestrict_t<decltype(end_)> it_ = hxlower_bound(hxforward<range_t_>(range_), value_, less_t_{});
210 return (it_ != end_ && !less_t_{}(value_, *it_)) ? it_ : end_;
211}
212
215template<hxrange_concept_ range_t_, typename callable_t_>
217hxsize_t hxcount_if(range_t_&& range_, callable_t_&& callable_) {
218 hxrestrict_t<decltype(range_.begin())> it_(range_.begin());
219 hxsize_t count_ = hxsize_t{0};
220 for(const auto end_ = range_.end(); it_ != end_; ++it_) {
221 if(hxforward<callable_t_>(callable_)(*it_)) {
222 ++count_;
223 }
224 }
225 return count_;
226}
227
231template<hxrange_concept_ range0_t_, hxrange_concept_ range1_t_, typename equal_t_>
233bool hxequal_range(range0_t_&& range0_, range1_t_&& range1_, const equal_t_& equal_) {
234 hxrestrict_t<decltype(range0_.begin())> begin0_(range0_.begin());
235 const auto end0_ = range0_.end();
236 hxrestrict_t<decltype(range1_.begin())> begin1_(range1_.begin());
237 const auto end1_ = range1_.end();
238#if HX_CPLUSPLUS >= 202002L
239 if constexpr(requires(const decltype(begin0_)& a_, const decltype(begin0_)& b_) { { b_ - a_ }; }
240 && requires(const decltype(begin1_)& a_, const decltype(begin1_)& b_) { { b_ - a_ }; }) {
241 if((end0_ - begin0_) != (end1_ - begin1_)) { return false; }
242 while(begin0_ != end0_) {
243 if(!equal_(*begin0_, *begin1_)) { return false; }
244 ++begin0_; ++begin1_;
245 }
246 return true;
247 }
248 else
249#endif
250 {
251 while(begin0_ != end0_ && begin1_ != end1_) {
252 if(!equal_(*begin0_, *begin1_)) { return false; }
253 ++begin0_; ++begin1_;
254 }
255 return begin0_ == end0_ && begin1_ == end1_;
256 }
257}
258
261template<hxrange_concept_ range0_t_, hxrange_concept_ range1_t_>
263bool hxequal_range(range0_t_&& range0_, range1_t_&& range1_) {
264 const auto begin0_ = range0_.begin();
266 hxforward<range1_t_>(range1_), hxkey_equal_t<decltype(*begin0_)>{});
267}
268
272template<typename T_, typename... args_t_>
274T_ hxexchange(T_& obj_, args_t_&&... args_) noexcept {
275 T_ old_(hxmove(obj_));
276 obj_ = T_(hxforward<args_t_>(args_)...);
277 return old_;
278}
279
283template<hxrange_concept_ range_t_, typename callable_t_>
285auto hxfind_if(range_t_&& range_, callable_t_&& callable_) -> decltype(range_.begin()) {
286 hxrestrict_t<decltype(range_.begin())> it_(range_.begin());
287 const auto end_ = range_.end();
288 for(; it_ != end_; ++it_) {
289 if(hxforward<callable_t_>(callable_)(*it_)) {
290 return it_;
291 }
292 }
293 return end_;
294}
295
299template<hxrange_concept_ range_t_, typename callable_t_>
301callable_t_ hxfor_each(range_t_&& range_, callable_t_&& callable_) {
302 hxrestrict_t<decltype(range_.begin())> it_(range_.begin());
303 for(const auto end_ = range_.end(); it_ != end_; ++it_) {
304 hxforward<callable_t_>(callable_)(*it_);
305 }
306 return hxforward<callable_t_>(callable_);
307}
308
314template<hxrange_concept_ range0_t_, hxrange_concept_ range1_t_, typename equal_t_, typename less_t_>
316bool hxless_range(range0_t_&& range0_, range1_t_&& range1_, const equal_t_& equal_,
317 const less_t_& less_) {
318 hxrestrict_t<decltype(range0_.begin())> begin0_(range0_.begin());
319 const auto end0_ = range0_.end();
320 hxrestrict_t<decltype(range1_.begin())> begin1_(range1_.begin());
321 const auto end1_ = range1_.end();
322 while(begin0_ != end0_ && begin1_ != end1_) {
323 if(!equal_(*begin0_, *begin1_)) { return less_(*begin0_, *begin1_); }
324 ++begin0_; ++begin1_;
325 }
326 return begin0_ == end0_ && begin1_ != end1_;
327}
328
332template<hxrange_concept_ range0_t_, hxrange_concept_ range1_t_>
334bool hxless_range(range0_t_&& range0_, range1_t_&& range1_) {
335 const auto begin0_ = range0_.begin();
337 hxforward<range1_t_>(range1_), hxkey_equal_t<decltype(*begin0_)>{},
338 hxkey_less_t<decltype(*begin0_)>{});
339}
340
347template<hxrandom_range_concept_ range_t_, typename value_t_, typename less_t_>
349auto hxlower_bound(range_t_&& range_, const value_t_& value_, const less_t_& less_)
350 -> decltype(range_.begin()) {
351 using iterator_t_ = hxrestrict_t<decltype(range_.begin())>;
352 iterator_t_ begin_ = range_.begin();
353 // Does not dereference null pointer args.
354 hxsize_t count_ = range_.end() - begin_;
355 while(count_ > hxsize_t{0}) {
356 const hxsize_t step_ = count_ >> 1;
357 const iterator_t_ mid_ = begin_ + step_;
358 if(less_(*mid_, value_)) {
359 begin_ = mid_ + hxsize_t{1};
360 count_ -= step_ + hxsize_t{1};
361 }
362 else {
363 count_ = step_;
364 }
365 }
366 return begin_;
367}
368
371template<hxrandom_range_concept_ range_t_, typename value_t_>
373auto hxlower_bound(range_t_&& range_, const value_t_& value_) -> decltype(range_.begin()) {
374 const auto begin_ = range_.begin();
375 return hxlower_bound(hxforward<range_t_>(range_), value_,
376 hxkey_less_t<decltype(*begin_)>{});
377}
378
384template<hxrandom_range_concept_ range_t_, typename value_t_, typename less_t_>
386auto hxupper_bound(range_t_&& range_, const value_t_& value_, const less_t_& less_)
387 -> decltype(range_.begin()) {
388 using iterator_t_ = hxrestrict_t<decltype(range_.begin())>;
389 iterator_t_ begin_ = range_.begin();
390 // Does not dereference null pointer args.
391 hxsize_t count_ = range_.end() - begin_;
392 while(count_ > hxsize_t{0}) {
393 const hxsize_t step_ = count_ >> 1;
394 const iterator_t_ mid_ = begin_ + step_;
395 if(!less_(value_, *mid_)) {
396 begin_ = mid_ + hxsize_t{1};
397 count_ -= step_ + hxsize_t{1};
398 }
399 else {
400 count_ = step_;
401 }
402 }
403 return begin_;
404}
405
408template<hxrandom_range_concept_ range_t_, typename value_t_>
410auto hxupper_bound(range_t_&& range_, const value_t_& value_) -> decltype(range_.begin()) {
411 const auto begin_ = range_.begin();
412 return hxupper_bound(hxforward<range_t_>(range_), value_,
413 hxkey_less_t<decltype(*begin_)>{});
414}
415
416HX_NS_END_
hxkey_equal_t<T> - A constexpr callable that returns true if two objects are equivalent.
Definition hxkey.hpp:57
hxkey_less_t<T> - A constexpr callable that returns true if the first object is less than the second.
Definition hxkey.hpp:91
hxrange - Wraps an iterator pair [begin, end) for use with algorithms on that pair.
Definition hxrange.hpp:94
constexpr iterator_t_ end(void) const
Returns an iterator one past the last element.
Definition hxrange.hpp:126
constexpr hxrange(iterator_t_ begin_, size_t size_)
Constructs from an iterator and a length.
Definition hxrange.hpp:117
constexpr hxrange(iterator_t_ begin_, hxsize_t size_)
Constructs from an iterator and a length.
Definition hxrange.hpp:111
constexpr hxrange(iterator_t_ begin_, iterator_t_ end_)
Constructs from the iterator pair [begin, end).
Definition hxrange.hpp:105
constexpr hxrange(T(&array_)[N_])
Constructs from the C array array.
Definition hxrange.hpp:99
constexpr iterator_t_ begin(void) const
Returns an iterator to the first element.
Definition hxrange.hpp:122
hxconvertible_to - A concept that requires one type to be convertible to another.
Definition hxutility.h:255
hxsame_as - A concept that requires two types to be the same.
Definition hxutility.h:265
User-specializable key-equal, key-less, and key-hash callables.
constexpr T hxexchange(T &obj_, args_t_ &&... args_) noexcept
hxexchange - Replaces obj with a T constructed from args and returns the old value of obj.
Definition hxrange.hpp:274
constexpr bool hxany_of(range_t_ &&range_, callable_t_ &&callable_)
hxany_of - Returns true if the predicate callable returns true for at least one element of range.
Definition hxrange.hpp:167
constexpr bool hxequal_range(range0_t_ &&range0_, range1_t_ &&range1_, const equal_t_ &equal_)
hxequal_range - Returns true if range0 and range1 have the same length and equal returns true for eve...
Definition hxrange.hpp:233
constexpr bool hxless_range(range0_t_ &&range0_, range1_t_ &&range1_, const equal_t_ &equal_, const less_t_ &less_)
hxless_range - Returns true if range0 is lexicographically less than range1, using equal to detect ma...
Definition hxrange.hpp:316
constexpr bool hxall_of(range_t_ &&range_, callable_t_ &&callable_)
hxall_of - Returns true if the predicate callable returns true for every element of range.
Definition hxrange.hpp:152
constexpr hxsize_t hxcount_if(range_t_ &&range_, callable_t_ &&callable_)
hxcount_if - Returns the number of elements of range for which the predicate callable returns true.
Definition hxrange.hpp:217
constexpr iterator_t_ hxbinary_search(iterator_t_ begin_, iterator_t_ end_, const value_t_ &value_, const less_t_ &less_)
hxbinary_search - Performs a binary search for value in the sorted range [begin, end).
Definition hxrange.hpp:184
constexpr auto hxfind_if(range_t_ &&range_, callable_t_ &&callable_) -> decltype(range_.begin())
hxfind_if - Returns an iterator to the first element of range for which the predicate callable return...
Definition hxrange.hpp:285
constexpr auto hxupper_bound(range_t_ &&range_, const value_t_ &value_, const less_t_ &less_) -> decltype(range_.begin())
hxupper_bound - Returns the first position in the sorted range whose element is ordered after value.
Definition hxrange.hpp:386
HX_NS_BEGIN_ constexpr auto hxlower_bound(range_t_ &&range_, const value_t_ &value_, const less_t_ &less_) -> decltype(range_.begin())
hxlower_bound - Returns the first position in the sorted range where value could be inserted without ...
Definition hxrange.hpp:349
constexpr callable_t_ hxfor_each(range_t_ &&range_, callable_t_ &&callable_)
hxfor_each - Applies the callable to each element of range in order.
Definition hxrange.hpp:301
constexpr hxrange< iterator_t_ > hxmake_range(iterator_t_ begin_, iterator_t_ end_)
hxmake_range - Returns an hxrange deduced from the iterator pair [begin, end).
Definition hxrange.hpp:139
#define hxinline
hxinline - Force a function to be inlined into its callers.
Definition hxsettings.h:125
#define hxattr_nodiscard
hxattr_nodiscard - Indicates the caller should not discard the return value.
Definition hxsettings.h:98
#define hxattr_flatten
hxattr_flatten - Inline every call inside a function's body into it, recursively, regardless of the c...
Definition hxsettings.h:90
#define hxconstexpr
hxconstexpr - Enables C++23 compatable constexpr usage for functions as that has support for destruct...
Definition hxsettings.h:266
typename hxrestrict_t_< T >::type hxrestrict_t
hxrestrict_t - Adds the __restrict keyword to C++ pointers.
Definition hxutility.h:287
constexpr T && hxforward(hxremove_reference_t< T > &&x_)
hxforward - Implements std::forward.
Definition hxutility.h:353
constexpr hxremove_reference_t< T > && hxmove(T &&t_)
hxmove - Implements std::move.
Definition hxutility.h:407
Provides core macros, memory management and feature detection.
ptrdiff_t hxsize_t
hxsize_t - A signed size type, same as ssize_t or ptrdiff_t.
Definition libhatchet.h:207