diff --git a/libvmake/vmake.hpp b/libvmake/vmake.hpp index 6494178..669eb37 100644 --- a/libvmake/vmake.hpp +++ b/libvmake/vmake.hpp @@ -22,8 +22,7 @@ struct sequence_terminated_error : std::exception { namespace details { template -auto is_sequence_helper(char) - -> decltype( +auto is_sequence_helper(char) -> decltype( std::declval()() , std::declval().is_terminated() , typename std::enable_if()()) @@ -44,6 +43,7 @@ namespace polyfill { using std::optional; using std::as_const; +using std::apply; #else @@ -53,6 +53,22 @@ template struct add_const_t { using type = const T; }; template constexpr typename add_const_t::type& as_const(T& t) noexcept { return t; } template void as_const(const T&&) = delete; +namespace details { + +template +decltype(auto) apply_helper(Func &&f, Tuple &&t, std::index_sequence) { + return f(std::get(std::forward(t))...); +} + +} + +template +decltype(auto) apply(Func &&f, Tuple &&t) { + return details::apply_helper(std::forward(f), std::forward(t) + , std::make_index_sequence::type>::value>()); +} + #endif } // namespace polyfill @@ -70,7 +86,7 @@ struct iota_sequence { return false; } - auto operator()() { + decltype(auto) operator()() { return start++; } }; @@ -87,7 +103,7 @@ struct ranged_sequence { return !(start < end); } - auto operator()() { + decltype(auto) operator()() { if (start == end) throw sequence_terminated_error(); return start++; } @@ -106,7 +122,7 @@ struct ranged_step_sequence { return !(start < end); } - auto operator()() { + decltype(auto) operator()() { if (start == end) throw sequence_terminated_error(); T res = start; start += step; @@ -129,8 +145,8 @@ inline auto range(Val &&start, Val &&end) { template inline auto range(Val &&start, Val &&end, Val &&step) { - return details::ranged_step_sequence::type>(std::forward(start) - , std::forward(end), std::forward(step)); + return details::ranged_step_sequence::type>( + std::forward(start), std::forward(end), std::forward(step)); } namespace details { @@ -171,7 +187,7 @@ struct ranged_iterator_extractor { return cur == end; } - auto operator()() { + decltype(auto) operator()() { // WARN: use for strange iterators such as std::istream_iterator // do NOT try to optimize this into *it++ if (cur == end) throw sequence_terminated_error(); @@ -194,7 +210,7 @@ struct iterator_extractor { return false; } - auto operator()() { + decltype(auto) operator()() { // WARN: use for strange iterators such as std::istream_iterator // do NOT try to optimize this into *it++ if (added) return *++it; @@ -238,7 +254,7 @@ struct generator { return false; } - auto operator()() { + decltype(auto) operator()() { return g(); } }; @@ -272,7 +288,7 @@ struct limitor { return lim <= 0 || g.is_terminated(); } - auto operator()() { + decltype(auto) operator()() { if (lim-- > 0) return g(); else throw sequence_terminated_error(); } @@ -319,24 +335,37 @@ inline auto repeat_n(Tval &&x, size_t n) { namespace details { -template -inline bool concat_terminate_helper(T &g, std::index_sequence seq) { - bool res = true; - void(std::array{ - (!res || std::get(g).is_terminated() || (res = false))... - }); - return res; +inline constexpr bool concat_terminate_helper() noexcept { + return true; } -template -inline Res concat_call_helper(T &g, std::index_sequence seq) { - polyfill::optional x; - void(std::array{ - (x.has_value() || std::get(g).is_terminated() - || (x.emplace(std::move(std::get(g)()))))... - }); - if (!x.has_value()) throw sequence_terminated_error(); - return *x; +template +inline bool concat_terminate_helper(Seq& f, Seqs& ...rest) noexcept { + if (!f.is_terminated()) return false; + return concat_terminate_helper(rest...); +} + +template +inline auto concat_terminate_applier(Tuple &t, std::index_sequence) noexcept { + return polyfill::apply(concat_terminate_helper< + typename std::tuple_element::type...>, t); +} + +template +inline decltype(auto) concat_call_helper(Seq& f, Seqs& ...rest) { + if (f.is_terminated()) return concat_call_helper(rest...); + return f(); +} + +template +inline decltype(auto) concat_call_helper(Seq &f) { + return f(); +} + +template +inline decltype(auto) concat_call_applier(Tuple &t, std::index_sequence) { + return polyfill::apply(concat_call_helper< + typename std::tuple_element::type...>, t); } template @@ -351,11 +380,11 @@ struct concator { concator(const concator&) = default; bool is_terminated() const noexcept { - return concat_terminate_helper(g, std::make_index_sequence()); + return concat_terminate_applier(g, std::make_index_sequence()); } - auto operator()() { - return concat_call_helper(g, std::make_index_sequence()); + decltype(auto) operator()() { + return concat_call_applier(g, std::make_index_sequence()); } }; @@ -384,7 +413,7 @@ struct transformer { return g.is_terminated(); } - auto operator()() { + decltype(auto) operator()() { return f(g()); } }; @@ -394,7 +423,8 @@ struct transformer { template inline auto transform(Gen &&g, Func &&f) { return details::transformer::type - , typename std::decay::type>(std::forward(g), std::forward(f)); + , typename std::decay::type>(std::forward(g) + , std::forward(f)); } template @@ -409,7 +439,7 @@ struct filteror { Pred p; mutable polyfill::optional preview; - filteror(Gen &&g, Pred &&p) : g(std::forward(g)), p(std::forward(p)), preview() { + filteror(Gen &&g, Pred &&p) : g(std::forward(g)), p(std::forward(p)) { _find_next(); }; @@ -419,7 +449,7 @@ struct filteror { return !preview.has_value(); } - auto operator()() { + decltype(auto) operator()() { if (is_terminated()) throw sequence_terminated_error(); result res = std::move(*preview); preview.reset(); @@ -440,7 +470,8 @@ private: }; template -inline filteror::type, typename std::decay::type> filter(Gen &&g, Pred &&p) { +inline filteror::type + , typename std::decay::type> filter(Gen &&g, Pred &&p) { return {std::forward(g), std::forward(p)}; } @@ -564,19 +595,20 @@ struct unique_ints_sequence { Tval l, r; Engine rng; std::uniform_int_distribution dis; + bool halfed; std::unordered_set used; std::vector rest; - bool halfed; - unique_ints_sequence(Engine &&e, Tval &&l, Tval &&r) : l(l), r(r), rng(std::forward(e)) - , dis(std::forward(l), std::forward(r)), used(), rest(), halfed(false) {} + unique_ints_sequence(Engine &&e, Tval &&l, Tval &&r) : l(std::forward(l)) + , r(std::forward(r)), rng(std::forward(e)) + , dis(std::forward(l), std::forward(r)), halfed(false) {} bool is_terminated() const noexcept { return halfed && rest.empty(); } auto operator()() { - if (!halfed && (used.size() + 1) * 2 >= static_cast<_unsigned_Tval>(r - l + 1)) { + if (!halfed && Tval{(used.size() + 1) * 2} >= r - l + 1) { for (Tval i = l; i <= r; ++i) { if (!used.count(i)) rest.push_back(i); } @@ -598,18 +630,14 @@ struct unique_ints_sequence { return res; } } - -private: - using _unsigned_Tval = typename std::conditional::value - , typename std::make_unsigned::type, Tval>::type; }; }; template inline auto uniform_ints(require_unique_t _, Tval &&l, Tval &&r) { - return details::unique_ints_sequence::type, Engine>(Engine(make_seed()) - , std::forward(l), std::forward(r)); + return details::unique_ints_sequence::type, Engine>( + Engine(make_seed()), std::forward(l), std::forward(r)); } template @@ -641,55 +669,71 @@ inline OutputIt copy_n(OutputIt it, size_t n, Gen&& g) { template inline auto output(std::basic_ostream& out, const char *delim, Gen &&g) { - return copy(std::ostream_iterator::type::result>(out, delim), std::move(g)); + return copy(std::ostream_iterator< + typename std::decay::type::result>(out, delim), std::move(g)); } template inline auto output(std::basic_ostream& out, Gen &&g) { - return copy(std::ostream_iterator::type::result>(out), std::move(g)); + return copy(std::ostream_iterator< + typename std::decay::type::result>(out), std::move(g)); } template inline auto output_n(std::basic_ostream& out, size_t n, const char *delim, Gen &&g) { - return copy_n(std::ostream_iterator::type::result>(out, delim), n, std::move(g)); + return copy_n(std::ostream_iterator< + typename std::decay::type::result>(out, delim), n, std::move(g)); } template inline auto output_n(std::basic_ostream& out, size_t n, Gen &&g) { - return copy_n(std::ostream_iterator::type::result>(out), n, std::move(g)); + return copy_n(std::ostream_iterator< + typename std::decay::type::result>(out), n, std::move(g)); } -template)> -inline auto outputln(std::basic_ostream& out, const char *delim, Gen &&g, const Endl &endl = std::endl) { - auto res = copy(std::ostream_iterator::type::result>(out, delim), std::move(g)); +template)> +inline auto outputln(std::basic_ostream& out, const char *delim + , Gen &&g, const Endl &endl = std::endl) { + auto res = copy(std::ostream_iterator< + typename std::decay::type::result>(out, delim), std::forward(g)); out << endl; return res; } -template)> -inline auto outputln(std::basic_ostream& out, Gen &&g, const Endl &endl = std::endl) { - auto res = copy(std::ostream_iterator::type::result>(out), std::move(g)); +template)> +inline auto outputln(std::basic_ostream& out + , Gen &&g, const Endl &endl = std::endl) { + auto res = copy(std::ostream_iterator< + typename std::decay::type::result>(out), std::forward(g)); out << endl; return res; } -template)> +template)> inline auto outputln_n(std::basic_ostream& out, size_t n , const char *delim, Gen &&g, const Endl &endl = std::endl) { - auto res = copy_n(std::ostream_iterator::type::result>(out, delim), n, std::move(g)); + auto res = copy_n(std::ostream_iterator< + typename std::decay::type::result>(out, delim), n, std::forward(g)); out << endl; return res; } -template)> -inline auto outputln_n(std::basic_ostream& out, size_t n, Gen &&g, const Endl &endl = std::endl) { - auto res = copy_n(std::ostream_iterator::type::result>(out), n, std::move(g)); +template)> +inline auto outputln_n(std::basic_ostream& out, size_t n + , Gen &&g, const Endl &endl = std::endl) { + auto res = copy_n(std::ostream_iterator< + typename std::decay::type::result>(out), n, std::forward(g)); out << endl; return res; } template)> -inline void outputln(std::basic_ostream& out, const Endl &endl = std::endl) { +inline void outputln(std::basic_ostream& out + , const Endl &endl = std::endl) { out << endl; }