Skip to content

Commit 380bf13

Browse files
authored
merge develop
2 parents b76ee93 + fa5fedb commit 380bf13

6 files changed

Lines changed: 231 additions & 22 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.24)
22

33
project(
44
dice-template-library
5-
VERSION 1.18.0
5+
VERSION 1.19.0
66
DESCRIPTION
77
"This template library is a collection of template-oriented code that we, the Data Science Group at UPB, found pretty handy. It contains: `switch_cases` (Use runtime values in compile-time context), `integral_template_tuple` (Create a tuple-like structure that instantiates a template for a range of values), `integral_template_variant` (A wrapper type for `std::variant` guarantees to only contain variants of the form `T<IX>` and `for_{types,values,range}` (Compile time for loops for types, values or ranges))."
88
HOMEPAGE_URL "https://dice-research.org/")

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ A C++20 compatible compiler. Code was only tested on x86_64.
167167
## Include it in your projects
168168
### Conan
169169
You can use it with [conan](https://conan.io/).
170-
To do so, you need to add `dice-template-library/1.18.0` to the `[requires]` section of your conan file.
170+
To do so, you need to add `dice-template-library/1.19.0` to the `[requires]` section of your conan file.
171171

172172
## Build and Run Tests and Examples
173173

include/dice/template-library/ranges.hpp

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <algorithm>
55
#include <functional>
6+
#include <limits>
67
#include <ranges>
78
#include <set>
89
#include <unordered_set>
@@ -320,39 +321,76 @@ namespace dice::template_library {
320321

321322

322323
namespace dice::template_library {
324+
325+
template<typename S, typename T>
326+
concept step_for = std::is_default_constructible_v<S> && requires (T start, T const stop, S step) {
327+
{ start <= stop } -> std::convertible_to<bool>;
328+
{ start >= stop } -> std::convertible_to<bool>;
329+
330+
start += step;
331+
};
332+
323333
namespace ranges_algo_detail {
324334

325335
// The view that represents the generated sequence.
326336
// range generator view (python-like iota with step)
327-
template<std::integral T>
328-
struct range_generator_view : std::ranges::view_interface<range_generator_view<T>> {
337+
template<typename T, step_for<T> S>
338+
struct range_generator_view : std::ranges::view_interface<range_generator_view<T, S>> {
329339
struct iterator;
330340
using sentinel = std::default_sentinel_t;
331341

332342
private:
333343
T start_;
334344
T stop_;
335-
std::make_signed_t<T> step_;
345+
S step_;
336346

337347
public:
338-
explicit constexpr range_generator_view(T start, T stop, std::make_signed_t<T> step) noexcept
348+
explicit constexpr range_generator_view(T start, T stop, S step)
339349
: start_{start},
340350
stop_{stop},
341351
step_{step} {
352+
353+
if (step == S{}) [[unlikely]] {
354+
throw std::invalid_argument{"range: step must not be the zero element/the additive identity"};
355+
}
342356
}
343357

344358
constexpr iterator begin() const noexcept {
345359
return iterator{*this, start_};
346360
}
347361

348-
constexpr sentinel end() const noexcept {
362+
static constexpr sentinel end() noexcept {
349363
return std::default_sentinel;
350364
}
365+
366+
constexpr size_t size() const noexcept requires (std::integral<T> && std::integral<S>) {
367+
// Math for calculating result: ceil(|stop_ - start_| / |step_|)
368+
// For integers we need to adjust the formula to avoid overflows, conversions and inefficient operations.
369+
// Note: ceil(a / b) = (a + b - 1) / b
370+
371+
if (start_ <= stop_) {
372+
// forward
373+
if (step_ < 0) {
374+
// wrong direction
375+
return 0;
376+
}
377+
378+
return (stop_ - start_ + step_ - 1) / step_;
379+
} else {
380+
// backward
381+
if (step_ > 0) {
382+
// wrong direction
383+
return 0;
384+
}
385+
386+
return (start_ - stop_ + -step_ - 1) / -step_;
387+
}
388+
}
351389
};
352390

353391
// The iterator that generates the numbers on the fly.
354-
template<std::integral T>
355-
struct range_generator_view<T>::iterator {
392+
template<typename T, step_for<T> S>
393+
struct range_generator_view<T, S>::iterator {
356394
using iterator_category = std::input_iterator_tag;
357395
using value_type = T;
358396
using difference_type = std::ptrdiff_t;
@@ -382,7 +420,7 @@ namespace dice::template_library {
382420
friend constexpr bool operator==(iterator const &self, std::default_sentinel_t) noexcept {
383421
// The end is reached if the step is positive and value is >= stop,
384422
// or if the step is negative and value is <= stop.
385-
if (self.parent_->step_ > 0) {
423+
if (self.parent_->step_ > S{}) {
386424
return self.value_ >= self.parent_->stop_;
387425
}
388426
return self.value_ <= self.parent_->stop_;
@@ -402,20 +440,19 @@ namespace dice::template_library {
402440
* - `range<T>(start, stop)`: Generates [start,stop).
403441
* - `range<T>(start, stop, step)`: Generates numbers from start, incrementing by step, until stop is met or passed.
404442
*/
405-
template<std::integral T, typename S = T>
443+
template<typename T, typename S>
406444
constexpr auto range(T start, T stop, S step) noexcept {
407-
static_assert(std::is_integral_v<S>, "Step must be an integral type.");
408-
return ranges_algo_detail::range_generator_view<T>(start, stop, static_cast<std::make_signed_t<T>>(step));
445+
return ranges_algo_detail::range_generator_view<T, S>(start, stop, step);
409446
}
410447

411-
template<std::integral T>
448+
template<typename T> requires (std::is_constructible_v<T, int> && step_for<T, T>)
412449
constexpr auto range(T start, T stop) noexcept {
413-
return ranges_algo_detail::range_generator_view<T>(start, stop, 1);
450+
return ranges_algo_detail::range_generator_view<T, T>(start, stop, T(1));
414451
}
415452

416-
template<std::integral T>
453+
template<typename T> requires (std::is_default_constructible_v<T> && std::is_constructible_v<T, int>)
417454
constexpr auto range(T stop) noexcept {
418-
return ranges_algo_detail::range_generator_view<T>(static_cast<T>(0), stop, 1);
455+
return ranges_algo_detail::range_generator_view<T, T>(T{}, stop, T(1));
419456
}
420457

421458
}// namespace dice::template_library

include/dice/template-library/type_list.hpp

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,35 @@ namespace dice::template_library::type_list {
264264
using find_if_t = typename find_if<TL, pred>::type;
265265

266266

267+
namespace detail_position {
268+
template<typename TL, auto pred, size_t ix>
269+
struct position;
270+
271+
template<auto pred, size_t ix>
272+
struct position<type_list<>, pred, ix> {
273+
};
274+
275+
template<typename T, typename ...Ts, auto pred, size_t ix>
276+
requires (!std::invoke(pred, std::type_identity<T>{}))
277+
struct position<type_list<T, Ts...>, pred, ix> : position<type_list<Ts...>, pred, ix + 1> {
278+
};
279+
280+
template<typename T, typename ...Ts, auto pred, size_t ix>
281+
requires (std::invoke(pred, std::type_identity<T>{}))
282+
struct position<type_list<T, Ts...>, pred, ix> : std::integral_constant<size_t, ix> {
283+
};
284+
} // namespace detail_position
285+
286+
/**
287+
* Searches for an element in the type list, returning the first position where the predicate returns true.
288+
*/
289+
template<typename TL, auto pred>
290+
using position = detail_position::position<TL, pred, 0>;
291+
292+
template<typename TL, auto pred>
293+
inline constexpr size_t position_v = position<TL, pred>::value;
294+
295+
267296
/**
268297
* Check if a particular type is present in the type list.
269298
*
@@ -356,32 +385,70 @@ namespace dice::template_library::type_list {
356385
* A marker type to indicate a failed operation
357386
* when using opt
358387
*/
359-
struct nullopt {};
388+
struct nullopt {
389+
constexpr bool operator==(nullopt const &other) const noexcept = default;
390+
};
391+
392+
393+
namespace detail_opt {
394+
395+
template<typename T>
396+
concept type_present = requires {
397+
typename T::type;
398+
};
399+
400+
template<typename T>
401+
concept value_present = requires {
402+
T::value;
403+
};
404+
405+
} // namespace detail_opt
360406

361407
/**
362408
* Can be used in combination with any operation that may fail.
363-
* By default, failing operations will not provide a `type` member typedef.
409+
* By default, failing operations will not provide a `type` member typedef / a static constexpr value.
364410
* When using opt, the member typedef `type` will always be present. In case the operation failed the type will be `nullopt`.
411+
* Additionally, the static constexpr value will always be present. In case the operation failed the static constexpr value will be `nullopt{}`
365412
*
366413
* @example
367414
* @code
368415
* using X = first_t<type_list<>>; // compilation failure, first has no `type` typedef
369416
* using X = opt_t<first<type_list<>>; // compilation success, X is nullopt
370417
* @endcode
371418
*/
372-
template<typename T, typename = void>
419+
template<typename T>
373420
struct opt {
374421
using type = nullopt;
422+
static constexpr auto value = nullopt{};
423+
};
424+
425+
template<typename T>
426+
requires (detail_opt::type_present<T> && !detail_opt::value_present<T>)
427+
struct opt<T> {
428+
using type = typename T::type;
429+
static constexpr auto value = nullopt{};
430+
};
431+
432+
template<typename T>
433+
requires (!detail_opt::type_present<T> && detail_opt::value_present<T>)
434+
struct opt<T> {
435+
using type = nullopt;
436+
static constexpr auto value = T::value;
375437
};
376438

377439
template<typename T>
378-
struct opt<T, std::void_t<typename T::type>> {
440+
requires (detail_opt::type_present<T> && detail_opt::value_present<T>)
441+
struct opt<T> {
379442
using type = typename T::type;
443+
static constexpr auto value = T::value;
380444
};
381445

382446
template<typename T>
383447
using opt_t = typename opt<T>::type;
384448

449+
template<typename T>
450+
inline constexpr auto opt_v = opt<T>::value;
451+
385452

386453
namespace detail_for_each {
387454
template<typename ...Ts, typename F>

0 commit comments

Comments
 (0)