diff --git a/sprout/algorithm/find_end.hpp b/sprout/algorithm/find_end.hpp index 09c47694..e175a493 100644 --- a/sprout/algorithm/find_end.hpp +++ b/sprout/algorithm/find_end.hpp @@ -73,8 +73,7 @@ namespace sprout { } template inline SPROUT_CONSTEXPR typename std::enable_if< - sprout::is_constant_distance_iterator::value - && sprout::is_constant_distance_iterator::value, + sprout::is_constant_distance_iterator::value && sprout::is_constant_distance_iterator::value, RandomAccessIterator1 >::type find_end( diff --git a/sprout/detail/algorithm/search_one.hpp b/sprout/detail/algorithm/search_one.hpp index fd7b7a02..c3b97c08 100644 --- a/sprout/detail/algorithm/search_one.hpp +++ b/sprout/detail/algorithm/search_one.hpp @@ -30,7 +30,10 @@ namespace sprout { ; } template - inline SPROUT_CONSTEXPR RandomAccessIterator1 + inline SPROUT_CONSTEXPR typename std::enable_if< + sprout::is_constant_distance_iterator::value && sprout::is_constant_distance_iterator::value, + RandomAccessIterator1 + >::type search_one( RandomAccessIterator1 first1, RandomAccessIterator1 last1, RandomAccessIterator2 first2, RandomAccessIterator2 last2, BinaryPredicate pred, std::random_access_iterator_tag* diff --git a/sprout/random/linear_congruential.hpp b/sprout/random/linear_congruential.hpp index 3cc7d083..278ea766 100644 --- a/sprout/random/linear_congruential.hpp +++ b/sprout/random/linear_congruential.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include namespace sprout { @@ -86,6 +87,79 @@ namespace sprout { linear_congruential_engine(result, private_construct_t()) ); } + struct discard_init { + public: + unsigned long long exponent; + result_type b_gcd; + result_type a_zm1_over_gcd; + result_type a_km1_over_gcd; + }; + struct discard_pred { + public: + SPROUT_CONSTEXPR bool operator()(discard_init const& init) const { + return static_cast(init.exponent); + } + }; + struct discard_op { + public: + SPROUT_CONSTEXPR discard_init operator()(discard_init const& init) const { + typedef sprout::random::detail::const_mod mod_type; + return discard_init{ + init.exponent / 2, + init.b_gcd, + !(init.exponent % 2 == 1) ? init.a_zm1_over_gcd + : mod_type::mult_add( + init.b_gcd, + mod_type::mult(init.a_zm1_over_gcd, init.a_km1_over_gcd), + mod_type::add(init.a_zm1_over_gcd, init.a_km1_over_gcd) + ) + , + mod_type::mult_add( + init.b_gcd, + mod_type::mult(init.a_km1_over_gcd, init.a_km1_over_gcd), + mod_type::add(init.a_km1_over_gcd, init.a_km1_over_gcd) + ) + }; + } + }; + SPROUT_CONSTEXPR linear_congruential_engine const discard_impl_1_2(result_type b_gcd, result_type a_zm1_over_gcd) const { + typedef sprout::random::detail::const_mod mod_type; + return linear_congruential_engine( + mod_type::mult_add( + mod_type::mult_add(b_gcd, a_zm1_over_gcd, 1), + x_, + mod_type::mult(mod_type::invert((multiplier - 1) / b_gcd), mod_type::mult(increment, a_zm1_over_gcd)) + ), + private_construct_t() + ); + } + SPROUT_CONSTEXPR linear_congruential_engine const discard_impl_1_1(result_type b_inv, result_type a_z) const { + typedef sprout::random::detail::const_mod mod_type; + return linear_congruential_engine( + mod_type::mult_add(a_z, x_, mod_type::mult(mod_type::mult(increment, b_inv), a_z - 1)), + private_construct_t() + ); + } + SPROUT_CONSTEXPR linear_congruential_engine const discard_impl_1(unsigned long long z, result_type b_inv, result_type b_gcd) const { + typedef sprout::random::detail::const_mod mod_type; + return b_gcd == 1 ? discard_impl_1_1(b_inv, mod_type::pow(multiplier, z)) + : discard_impl_1_2( + b_gcd, + sprout::while_loop( + discard_init{z, b_gcd, 0, (multiplier - 1) / b_gcd}, + discard_pred(), + discard_op() + ).a_zm1_over_gcd + ) + ; + } + SPROUT_CONSTEXPR linear_congruential_engine const discard_impl(unsigned long long z, result_type b_inv) const { + typedef sprout::random::detail::const_mod mod_type; + return discard_impl_1( + z, b_inv, + mod_type::mult(multiplier - 1, b_inv) + ); + } public: SPROUT_CONSTEXPR linear_congruential_engine() : x_(init_seed()) @@ -134,6 +208,43 @@ namespace sprout { SPROUT_CONSTEXPR sprout::random::random_result const operator()() const { return generate(sprout::random::detail::const_mod::mult_add(a, x_, c)); } + SPROUT_CONSTEXPR linear_congruential_engine const discard(unsigned long long z) const { + typedef sprout::random::detail::const_mod mod_type; + return discard_impl(z, mod_type::invert(multiplier - 1)); + } + SPROUT_CXX14_CONSTEXPR void discard(unsigned long long z) { + typedef sprout::random::detail::const_mod mod_type; + result_type b_inv = mod_type::invert(multiplier - 1); + result_type b_gcd = mod_type::mult(multiplier - 1, b_inv); + if (b_gcd == 1) { + result_type a_z = mod_type::pow(multiplier, z); + x_ = mod_type::mult_add(a_z, x_, mod_type::mult(mod_type::mult(increment, b_inv), a_z - 1)); + } else { + result_type a_zm1_over_gcd = 0; + result_type a_km1_over_gcd = (multiplier - 1) / b_gcd; + unsigned long long exponent = z; + while (exponent) { + if (exponent % 2 == 1) { + a_zm1_over_gcd = mod_type::mult_add( + b_gcd, + mod_type::mult(a_zm1_over_gcd, a_km1_over_gcd), + mod_type::add(a_zm1_over_gcd, a_km1_over_gcd) + ); + } + a_km1_over_gcd = mod_type::mult_add( + b_gcd, + mod_type::mult(a_km1_over_gcd, a_km1_over_gcd), + mod_type::add(a_km1_over_gcd, a_km1_over_gcd) + ); + exponent /= 2; + } + x_ = mod_type::mult_add( + mod_type::mult_add(b_gcd, a_zm1_over_gcd, 1), + x_, + mod_type::mult(mod_type::invert((multiplier - 1) / b_gcd), mod_type::mult(increment, a_zm1_over_gcd)) + ); + } + } friend SPROUT_CONSTEXPR bool operator==(linear_congruential_engine const& lhs, linear_congruential_engine const& rhs) SPROUT_NOEXCEPT { return lhs.x_ == rhs.x_; } diff --git a/sprout/stateful.hpp b/sprout/stateful.hpp new file mode 100644 index 00000000..c43aca5b --- /dev/null +++ b/sprout/stateful.hpp @@ -0,0 +1,16 @@ +/*============================================================================= + Copyright (c) 2011-2015 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#ifndef SPROUT_STATEFUL_HPP +#define SPROUT_STATEFUL_HPP + +#include +#include +#include +#include + +#endif // #ifndef SPROUT_STATEFUL_HPP diff --git a/sprout/stateful/counter.hpp b/sprout/stateful/counter.hpp new file mode 100644 index 00000000..47c3f42d --- /dev/null +++ b/sprout/stateful/counter.hpp @@ -0,0 +1,107 @@ +/*============================================================================= + Copyright (c) 2011-2015 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#ifndef SPROUT_STATEFUL_COUNTER_HPP +#define SPROUT_STATEFUL_COUNTER_HPP + +#include +#include + +namespace sprout { +#ifndef SPROUT_CONFIG_DISABLE_CONSTEXPR + + namespace detail { + SPROUT_STATIC_CONSTEXPR std::size_t counter_default_call_limit = 128; + } // namespace detail + + namespace counter_detail { +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnon-template-friend" +#endif +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wundefined-inline" +#endif + template + struct tag { + friend SPROUT_CONSTEXPR int adl_counter(sprout::counter_detail::tag); + }; +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic pop +#endif + + template + struct state { + friend SPROUT_CONSTEXPR int adl_counter(sprout::counter_detail::tag) { + return N; + } + SPROUT_STATIC_CONSTEXPR int value = N - 1; + }; + template + SPROUT_CONSTEXPR_OR_CONST int sprout::counter_detail::state::value; + template<> + struct state<1> { + friend SPROUT_CONSTEXPR int adl_counter(sprout::counter_detail::tag<1>) { + return 1; + } + static SPROUT_CONSTEXPR int value = 0; + }; + SPROUT_CONSTEXPR_OR_CONST int sprout::counter_detail::state<1>::value; + + template())> + SPROUT_CONSTEXPR int counter( + int, sprout::counter_detail::tag + ) + { + return R; + } + SPROUT_CONSTEXPR int counter( + long, sprout::counter_detail::tag<0> + ) + { + return 0; + } + template + SPROUT_CONSTEXPR int counter( + long, sprout::counter_detail::tag, + int R = counter(0, sprout::counter_detail::tag()) + ) + { + return R; + } + } // namespace counter_detail + // + // counter + // counter_before + // + template< + std::size_t Limit = sprout::detail::counter_default_call_limit, + int R = sprout::counter_detail::state< + sprout::counter_detail::counter(0, sprout::counter_detail::tag()) + 1 + >::value + > + SPROUT_CONSTEXPR int counter() { + return R; + } + template< + std::size_t Limit = sprout::detail::counter_default_call_limit, + int R = sprout::counter_detail::state< + sprout::counter_detail::counter(0, sprout::counter_detail::tag()) + >::value + > + SPROUT_CONSTEXPR int counter_before() { + return R; + } + +#endif +} // namespace sprout + +#endif // #ifndef SPROUT_STATEFUL_COUNTER_HPP diff --git a/sprout/stateful/rand.hpp b/sprout/stateful/rand.hpp new file mode 100644 index 00000000..dc2b19a5 --- /dev/null +++ b/sprout/stateful/rand.hpp @@ -0,0 +1,196 @@ +/*============================================================================= + Copyright (c) 2011-2015 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#ifndef SPROUT_STATEFUL_RAND_HPP +#define SPROUT_STATEFUL_RAND_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sprout { +#ifndef SPROUT_CONFIG_DISABLE_CONSTEXPR + + namespace detail { + typedef sprout::random::default_random_engine rand_generator_type; + typedef SPROUT_WORKAROUND_DETAIL_UNIFORM_INT_DISTRIBUTION rand_distribution_type; + typedef sprout::random::random_result< + sprout::detail::rand_generator_type, + sprout::detail::rand_distribution_type + > rand_result_type; + + SPROUT_STATIC_CONSTEXPR std::size_t rand_default_seed = SPROUT_UNIQUE_SEED; + SPROUT_STATIC_CONSTEXPR std::size_t rand_default_call_limit = 128; + } // namespace detail + + namespace rand_detail { +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnon-template-friend" +#endif +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wundefined-inline" +#endif + template + struct tag { + friend SPROUT_CONSTEXPR int adl_counter(sprout::rand_detail::tag); + friend SPROUT_CONSTEXPR bool adl_is_srand(sprout::rand_detail::tag); + friend SPROUT_CONSTEXPR unsigned adl_seed(sprout::rand_detail::tag); + }; +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic pop +#endif + + template + struct state { + friend SPROUT_CONSTEXPR int adl_counter(sprout::rand_detail::tag) { + return N; + } + friend SPROUT_CONSTEXPR bool adl_is_srand(sprout::rand_detail::tag) { + return IsSrand; + } + friend SPROUT_CONSTEXPR unsigned adl_seed(sprout::rand_detail::tag) { + return Seed; + } + // generate a next random number + SPROUT_STATIC_CONSTEXPR sprout::detail::rand_result_type result + SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_INNER(( + !IsSrand ? sprout::rand_detail::state< + N - 1, + adl_is_srand(sprout::rand_detail::tag()), + adl_seed(sprout::rand_detail::tag()) + >::result() + : sprout::detail::rand_result_type( + Seed, + sprout::detail::rand_generator_type(Seed), + sprout::detail::rand_distribution_type(0, RAND_MAX) + ) + )) + ; + SPROUT_STATIC_CONSTEXPR int value = result; + }; + template + SPROUT_CONSTEXPR_OR_CONST sprout::detail::rand_result_type sprout::rand_detail::state::result + SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_OUTER(( + !IsSrand ? sprout::rand_detail::state< + N - 1, + adl_is_srand(sprout::rand_detail::tag()), + adl_seed(sprout::rand_detail::tag()) + >::result() + : sprout::detail::rand_result_type( + 0, + sprout::detail::rand_generator_type(Seed), + sprout::detail::rand_distribution_type(0, RAND_MAX) + ) + )) + ; + template + SPROUT_CONSTEXPR_OR_CONST int sprout::rand_detail::state::value; + template + struct state<1, IsSrand, Seed> { + friend SPROUT_CONSTEXPR int adl_counter(sprout::rand_detail::tag<1>) { + return 1; + } + friend SPROUT_CONSTEXPR bool adl_is_srand(sprout::rand_detail::tag<1>) { + return IsSrand; + } + friend SPROUT_CONSTEXPR unsigned adl_seed(sprout::rand_detail::tag<1>) { + return Seed; + } + // generate a first random number between [0, RAND_MAX] + SPROUT_STATIC_CONSTEXPR sprout::detail::rand_result_type result + SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_INNER( + sprout::detail::rand_distribution_type(0, RAND_MAX) + (sprout::as_const(sprout::detail::rand_generator_type(!IsSrand ? sprout::detail::rand_default_seed : Seed))) + ) + ; + static SPROUT_CONSTEXPR int value = result; + }; + template + SPROUT_CONSTEXPR_OR_CONST sprout::detail::rand_result_type sprout::rand_detail::state<1, IsSrand, Seed>::result + SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_OUTER( + sprout::detail::rand_distribution_type(0, RAND_MAX) + (sprout::as_const(sprout::detail::rand_generator_type(!IsSrand ? sprout::detail::rand_default_seed : Seed))) + ) + ; + template + SPROUT_CONSTEXPR_OR_CONST int sprout::rand_detail::state<1, IsSrand, Seed>::value; + + template())> + SPROUT_CONSTEXPR int counter( + int, sprout::rand_detail::tag + ) + { + return R; + } + SPROUT_CONSTEXPR int counter( + long, sprout::rand_detail::tag<0> + ) + { + return 0; + } + template + SPROUT_CONSTEXPR int counter( + long, sprout::rand_detail::tag, + int R = counter(0, sprout::rand_detail::tag()) + ) + { + return R; + } + } // namespace rand_detail + // + // rand + // rand_before + // + template< + std::size_t Limit = sprout::detail::rand_default_call_limit, + int R = sprout::rand_detail::state< + sprout::rand_detail::counter(0, sprout::rand_detail::tag()) + 1 + >::value + > + SPROUT_CONSTEXPR int rand() { + return R; + } + + // + // srand + // srand_return + // + template< + unsigned Seed, + std::size_t Limit = sprout::detail::rand_default_call_limit, + int = sprout::rand_detail::state< + sprout::rand_detail::counter(0, sprout::rand_detail::tag()) + 1, + true, Seed + >::value + > + SPROUT_CXX14_CONSTEXPR void srand() {} + template< + unsigned Seed, + std::size_t Limit = sprout::detail::rand_default_call_limit, + int R = sprout::rand_detail::state< + sprout::rand_detail::counter(0, sprout::rand_detail::tag()) + 1, + true, Seed + >::value + > + SPROUT_CONSTEXPR unsigned srand_return() { + return R; + } + +#endif +} // namespace sprout + +#endif // #ifndef SPROUT_STATEFUL_RAND_HPP diff --git a/sprout/stateful/slot.hpp b/sprout/stateful/slot.hpp new file mode 100644 index 00000000..16e91e91 --- /dev/null +++ b/sprout/stateful/slot.hpp @@ -0,0 +1,181 @@ +/*============================================================================= + Copyright (c) 2011-2015 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#ifndef SPROUT_STATEFUL_SLOT_HPP +#define SPROUT_STATEFUL_SLOT_HPP + +#include +#include +#include +#include +#include + +namespace sprout { +#ifndef SPROUT_CONFIG_DISABLE_CONSTEXPR + + namespace detail { + SPROUT_STATIC_CONSTEXPR std::size_t slot_default_call_limit = 128; + } // namespace detail + + namespace slot_detail { +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnon-template-friend" +#endif +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wundefined-inline" +#endif + template + struct tag { + friend SPROUT_CONSTEXPR int adl_counter(sprout::slot_detail::tag); + friend SPROUT_CONSTEXPR int adl_id(sprout::slot_detail::tag); + friend SPROUT_CONSTEXPR std::intmax_t adl_value(sprout::slot_detail::tag); + template + friend SPROUT_CONSTEXPR std::intmax_t adl_get(sprout::slot_detail::tag, sprout::integral_constant); + }; +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic pop +#endif + + template + struct state { + friend SPROUT_CONSTEXPR int adl_counter(sprout::slot_detail::tag) { + return N; + } + friend SPROUT_CONSTEXPR int adl_id(sprout::slot_detail::tag) { + return ID; + } + friend SPROUT_CONSTEXPR std::intmax_t adl_value(sprout::slot_detail::tag) { + return Value; + } + template + friend SPROUT_CONSTEXPR std::intmax_t adl_get(sprout::slot_detail::tag, sprout::integral_constant) { + return get(); + } + template + static SPROUT_CONSTEXPR std::intmax_t get() { + return I == ID ? Value + : state< + N - 1, + adl_id(sprout::slot_detail::tag()), + adl_value(sprout::slot_detail::tag()) + >::template get() + ; + } + }; + template + struct state<1, ID, Value> { + friend SPROUT_CONSTEXPR int adl_counter(sprout::slot_detail::tag<1>) { + return 1; + } + friend SPROUT_CONSTEXPR int adl_id(sprout::slot_detail::tag<1>) { + return ID; + } + friend SPROUT_CONSTEXPR std::intmax_t adl_value(sprout::slot_detail::tag<1>) { + return Value; + } + template + friend SPROUT_CONSTEXPR std::intmax_t adl_get(sprout::slot_detail::tag<1>, sprout::integral_constant) { + return get(); + } + template + static SPROUT_CONSTEXPR std::intmax_t get() { + return SPROUT_ASSERT(I == ID), Value; + } + }; + + template())> + SPROUT_CONSTEXPR int counter( + int, sprout::slot_detail::tag + ) + { + return R; + } + SPROUT_CONSTEXPR int counter( + long, sprout::slot_detail::tag<0> + ) + { + return 0; + } + template + SPROUT_CONSTEXPR int counter( + long, sprout::slot_detail::tag, + int R = counter(0, sprout::slot_detail::tag()) + ) + { + return R; + } + + template(), sprout::integral_constant())> + SPROUT_CONSTEXPR std::intmax_t get( + int, sprout::slot_detail::tag + ) + { + return R; + } + template + SPROUT_CONSTEXPR std::intmax_t get( + long, sprout::slot_detail::tag<0> + ) + { + return 0; + } + template + SPROUT_CONSTEXPR std::intmax_t get( + long, sprout::slot_detail::tag, + std::intmax_t R = get(0, sprout::slot_detail::tag()) + ) + { + return R; + } + } // namespace slot_detail + // + // slot + // + template< + int I, + std::size_t Limit = sprout::detail::slot_default_call_limit, + std::intmax_t R = sprout::slot_detail::get(0, sprout::slot_detail::tag()) + > + SPROUT_CONSTEXPR std::intmax_t slot() { + return R; + } + // + // assign_slot + // assign_slot_return + // + template< + int I, + std::intmax_t Value, + std::size_t Limit = sprout::detail::slot_default_call_limit, + std::intmax_t = sprout::slot_detail::state< + sprout::slot_detail::counter(0, sprout::slot_detail::tag()) + 1, + I, Value + >::template get() + > + SPROUT_CXX14_CONSTEXPR void assign_slot() {} + template< + int I, + std::intmax_t Value, + std::size_t Limit = sprout::detail::slot_default_call_limit, + std::intmax_t R = sprout::slot_detail::state< + sprout::slot_detail::counter(0, sprout::slot_detail::tag()) + 1, + I, Value + >::template get() + > + SPROUT_CONSTEXPR std::intmax_t assign_slot_return() { + return R; + } + +#endif +} // namespace sprout + +#endif // #ifndef SPROUT_STATEFUL_SLOT_HPP diff --git a/testspr/header_all.hpp b/testspr/header_all.hpp index 51a5beea..741aafbb 100644 --- a/testspr/header_all.hpp +++ b/testspr/header_all.hpp @@ -60,7 +60,6 @@ #include #include #include -#include #include #include #include @@ -68,6 +67,8 @@ #include #include #include +#include +#include #include #include #include