From 41090efaf5703f1be5820056c73ad9e48bf962ce Mon Sep 17 00:00:00 2001 From: szdytom Date: Wed, 19 Jul 2023 21:49:49 +0800 Subject: [PATCH] [libvmake] add meta type vmake::is_sequence_t to check if a type is a valid sequence fixed a bug with vmake::range(start, end, step) added an example about how to define costum sequences --- libvmake/examples/custom_sequence.cpp | 26 +++++++++++++++ libvmake/vmake.hpp | 46 +++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 libvmake/examples/custom_sequence.cpp diff --git a/libvmake/examples/custom_sequence.cpp b/libvmake/examples/custom_sequence.cpp new file mode 100644 index 0000000..9f3c544 --- /dev/null +++ b/libvmake/examples/custom_sequence.cpp @@ -0,0 +1,26 @@ +#include "../vmake.hpp" +using namespace std; + +// equivlant to vmake::range(2, 11, 2) +struct my_sequence { + using result = int; + + int p; + my_sequence() : p(2) {} + + bool is_terminated() const noexcept { + return p > 10; + } + + int operator()() { + p += 2; + return p - 2; + } +}; + +int main() { + static_assert(vmake::is_sequence_t::value, "my_sequence is not a valid sequence!"); + vmake::outputln(cout, " ", my_sequence{}); + vmake::outputln(cout, " ", vmake::range(2, 11, 2)); + return 0; +} diff --git a/libvmake/vmake.hpp b/libvmake/vmake.hpp index 46146b7..1bdd12e 100644 --- a/libvmake/vmake.hpp +++ b/libvmake/vmake.hpp @@ -19,8 +19,26 @@ struct sequence_terminated_error : std::exception { } }; -namespace polyfill { +namespace details { +template +auto is_sequence_helper(char) + -> decltype( + std::declval()() + , std::declval().is_terminated() + , typename std::enable_if()()) + , typename T::result>::value, int>::type() + , std::true_type{}); + +template +auto is_sequence_helper(int) -> std::false_type; + +} + +template +using is_sequence_t = decltype(details::is_sequence_helper(' ')); + +namespace polyfill { #if __cplusplus >= 201703L @@ -46,7 +64,7 @@ struct iota_sequence { using result = T; T start; - iota_sequence(const T& start) : start(start) {} + iota_sequence(T&& start) : start(std::forward(start)) {} bool is_terminated() const noexcept { return false; @@ -62,10 +80,11 @@ struct ranged_sequence { using result = T; T start, end; - ranged_sequence(const T& start, const T& end) : start(start), end(end) {} + ranged_sequence(T&& start, T&& end) + : start(std::forward(start)), end(std::forward(end)) {} bool is_terminated() const noexcept { - return start == end; + return !(start < end); } auto operator()() { @@ -79,10 +98,12 @@ struct ranged_step_sequence { using result = T; T start, end, step; - ranged_step_sequence(const T& start, const T& end, const T& step) : start(start), end(end), step(step) {} + ranged_step_sequence(T&& start, T&& end, T&& step) + : start(std::forward(start)), end(std::forward(end)) + , step(std::forward(step)) {} bool is_terminated() const noexcept { - return start == end; + return !(start < end); } auto operator()() { @@ -657,6 +678,19 @@ inline void outputln(std::basic_ostream& out, const Endl &endl = out << endl; } +namespace tests { + +using empty_sequence_int = decltype(nothing()); + +static_assert(is_sequence_t::value, ""); +static_assert(is_sequence_t::value, ""); +static_assert(is_sequence_t(empty_sequence_int{}))>::value, ""); + +static_assert(!is_sequence_t::value, ""); +static_assert(!is_sequence_t>::value, ""); + +} + } #endif