diff --git a/sprout/config/compiler/clang.hpp b/sprout/config/compiler/clang.hpp index 72f6cc4b..787d46f1 100644 --- a/sprout/config/compiler/clang.hpp +++ b/sprout/config/compiler/clang.hpp @@ -21,8 +21,8 @@ # define SPROUT_NO_DELEGATING_CONSTRUCTORS #endif -//#if (__has_feature(cxx_constexpr) && (__GNUC__ >= 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) -//# define SPROUT_HAS_CONSTEXPR_CMATH_FUNCTION -//#endif +#if !defined(SPROUT_NO_CONSTEXPR) +# define SPROUT_WORKAROUND_NOT_TERMINATE_RECURSIVE_CONSTEXPR_FUNCTION_TEMPLATE +#endif #endif // #ifndef SPROUT_CONFIG_COMPILER_CLANG_HPP diff --git a/sprout/math/gcd.hpp b/sprout/math/gcd.hpp index ef970698..83b16690 100644 --- a/sprout/math/gcd.hpp +++ b/sprout/math/gcd.hpp @@ -6,6 +6,10 @@ #include #include #include +#ifdef SPROUT_WORKAROUND_NOT_TERMINATE_RECURSIVE_CONSTEXPR_FUNCTION_TEMPLATE +# include +# include +#endif namespace sprout { namespace math { @@ -31,28 +35,45 @@ namespace sprout { sprout::math::detail::gcd_euclidean(a, b) ); } - - template +#ifdef SPROUT_WORKAROUND_NOT_TERMINATE_RECURSIVE_CONSTEXPR_FUNCTION_TEMPLATE + template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary_2_1(unsigned shifts, sprout::array const& r, unsigned which); - template + template + inline SPROUT_CONSTEXPR BuiltInUnsigned + gcd_binary_2_1(unsigned shifts, sprout::array const& r, unsigned which); + template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary_2_2(unsigned shifts, sprout::array const& r, unsigned which) { - return !(r[ which ] & 1u) ? sprout::math::detail::gcd_binary_2_2( + return r[which] ? sprout::math::detail::gcd_binary_2_1(shifts, r, which) + : r[!which] << shifts + ; + } + template + inline SPROUT_CONSTEXPR BuiltInUnsigned + gcd_binary_2_2(unsigned shifts, sprout::array const& r, unsigned which) { + return throw std::runtime_error(SPROUT_RECURSIVE_FUNCTION_TEMPLATE_INSTANTIATION_EXCEEDED_MESSAGE), + BuiltInUnsigned() + ; + } + template + inline SPROUT_CONSTEXPR BuiltInUnsigned + gcd_binary_2_1(unsigned shifts, sprout::array const& r, unsigned which) { + return !(r[which] & 1u) ? sprout::math::detail::gcd_binary_2_1( shifts, which ? sprout::array{{r[0], BuiltInUnsigned(r[1] >> 1)}} : sprout::array{{BuiltInUnsigned(r[0] >> 1), r[1]}} , which ) - : r[!which] > r[which] ? sprout::math::detail::gcd_binary_2_1( + : r[!which] > r[which] ? sprout::math::detail::gcd_binary_2_2( shifts, which ^ 1u ? sprout::array{{r[0], BuiltInUnsigned(r[1] - r[0])}} : sprout::array{{BuiltInUnsigned(r[0] - r[1]), r[1]}} , which ^ 1u ) - : sprout::math::detail::gcd_binary_2_1( + : sprout::math::detail::gcd_binary_2_2( shifts, which ? sprout::array{{r[0], BuiltInUnsigned(r[1] - r[0])}} : sprout::array{{BuiltInUnsigned(r[0] - r[1]), r[1]}} @@ -61,18 +82,56 @@ namespace sprout { ) ; } - template + template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary_2_1(unsigned shifts, sprout::array const& r, unsigned which) { - return r[which] ? sprout::math::detail::gcd_binary_2_2(shifts, r, which) + return throw std::runtime_error(SPROUT_RECURSIVE_FUNCTION_TEMPLATE_INSTANTIATION_EXCEEDED_MESSAGE), + BuiltInUnsigned() + ; + } +#else + template + inline SPROUT_CONSTEXPR BuiltInUnsigned + gcd_binary_2_1(unsigned shifts, sprout::array const& r, unsigned which); + template + inline SPROUT_CONSTEXPR BuiltInUnsigned + gcd_binary_2_2(unsigned shifts, sprout::array const& r, unsigned which) { + return r[which] ? sprout::math::detail::gcd_binary_2_1(shifts, r, which) : r[!which] << shifts ; } + template + inline SPROUT_CONSTEXPR BuiltInUnsigned + gcd_binary_2_1(unsigned shifts, sprout::array const& r, unsigned which) { + return !(r[which] & 1u) ? sprout::math::detail::gcd_binary_2_1( + shifts, + which ? sprout::array{{r[0], BuiltInUnsigned(r[1] >> 1)}} + : sprout::array{{BuiltInUnsigned(r[0] >> 1), r[1]}} + , + which + ) + : r[!which] > r[which] ? sprout::math::detail::gcd_binary_2_2( + shifts, + which ^ 1u ? sprout::array{{r[0], BuiltInUnsigned(r[1] - r[0])}} + : sprout::array{{BuiltInUnsigned(r[0] - r[1]), r[1]}} + , + which ^ 1u + ) + : sprout::math::detail::gcd_binary_2_2( + shifts, + which ? sprout::array{{r[0], BuiltInUnsigned(r[1] - r[0])}} + : sprout::array{{BuiltInUnsigned(r[0] - r[1]), r[1]}} + , + which + ) + ; + } +#endif template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary_1(BuiltInUnsigned u, BuiltInUnsigned v, unsigned shifts = 0) { return (!(u & 1u) && !(v & 1u)) ? sprout::math::detail::gcd_binary_1(u >> 1, v >> 1, shifts + 1) - : sprout::math::detail::gcd_binary_2_2( + : sprout::math::detail::gcd_binary_2_1( shifts, sprout::array{{u, v}}, static_cast(u & 1u) ) ; diff --git a/sprout/random/uniform_01.hpp b/sprout/random/uniform_01.hpp index 0da25304..b702003d 100644 --- a/sprout/random/uniform_01.hpp +++ b/sprout/random/uniform_01.hpp @@ -6,6 +6,10 @@ #include #include #include +#ifdef SPROUT_WORKAROUND_NOT_TERMINATE_RECURSIVE_CONSTEXPR_FUNCTION_TEMPLATE +# include +# include +#endif namespace sprout { namespace random { @@ -49,24 +53,57 @@ namespace sprout { } }; private: - template - SPROUT_CONSTEXPR sprout::random::random_result generate_1( - Engine const& eng, - sprout::random::random_result const& rnd, - result_type result - ) const - { +#ifdef SPROUT_WORKAROUND_NOT_TERMINATE_RECURSIVE_CONSTEXPR_FUNCTION_TEMPLATE + template + SPROUT_CONSTEXPR sprout::random::random_result + generate_1(Engine const& eng, sprout::random::random_result const& rnd, result_type result) const { return result < result_type(1) ? sprout::random::random_result(result, rnd.engine(), *this) - : operator()(rnd.engine()) + : generate(rnd.engine(), rnd.engine()()) + ; + } + template + SPROUT_CONSTEXPR sprout::random::random_result + generate_1(Engine const& eng, sprout::random::random_result const& rnd, result_type result) const { + return throw std::runtime_error(SPROUT_RECURSIVE_FUNCTION_TEMPLATE_INSTANTIATION_EXCEEDED_MESSAGE), + sprout::random::random_result() + ; + } + template + SPROUT_CONSTEXPR sprout::random::random_result + generate(Engine const& eng, sprout::random::random_result const& rnd) const { + typedef typename Engine::result_type base_result; + return generate_1( + eng, + rnd, + result_type(rnd.result() - eng.min()) * ( + result_type(1) / ( + result_type(eng.max() - eng.min()) + result_type( + std::numeric_limits::is_integer ? 1 : 0 + ) + ) + ) + ); + } + template + SPROUT_CONSTEXPR sprout::random::random_result + generate(Engine const& eng, sprout::random::random_result const& rnd) const { + return throw std::runtime_error(SPROUT_RECURSIVE_FUNCTION_TEMPLATE_INSTANTIATION_EXCEEDED_MESSAGE), + sprout::random::random_result() + ; + } +#else + template + SPROUT_CONSTEXPR sprout::random::random_result + generate_1(Engine const& eng, sprout::random::random_result const& rnd, result_type result) const { + return result < result_type(1) + ? sprout::random::random_result(result, rnd.engine(), *this) + : generate(rnd.engine(), rnd.engine()()) ; } template - SPROUT_CONSTEXPR sprout::random::random_result generate( - Engine const& eng, - sprout::random::random_result const& rnd - ) const - { + SPROUT_CONSTEXPR sprout::random::random_result + generate(Engine const& eng, sprout::random::random_result const& rnd) const { typedef typename Engine::result_type base_result; return generate_1( eng, @@ -80,6 +117,7 @@ namespace sprout { ) ); } +#endif public: explicit SPROUT_CONSTEXPR uniform_01() {} diff --git a/sprout/workaround.hpp b/sprout/workaround.hpp new file mode 100644 index 00000000..55244bae --- /dev/null +++ b/sprout/workaround.hpp @@ -0,0 +1,7 @@ +#ifndef SPROUT_WORKAROUND_HPP +#define SPROUT_WORKAROUND_HPP + +#include +#include + +#endif // #ifndef SPROUT_WORKAROUND_HPP diff --git a/sprout/workaround/recursive_function_template.hpp b/sprout/workaround/recursive_function_template.hpp new file mode 100644 index 00000000..239dae60 --- /dev/null +++ b/sprout/workaround/recursive_function_template.hpp @@ -0,0 +1,39 @@ +#ifndef SPROUT_WORKAROUND_RECURSIVE_FUNCTION_TEMPLATE_HPP +#define SPROUT_WORKAROUND_RECURSIVE_FUNCTION_TEMPLATE_HPP + +#include +#include +#include + +// +// SPROUT_RECURSIVE_FUNCTION_TEMPLATE_INSTANTIATION_LIMIT +// +#ifndef SPROUT_RECURSIVE_FUNCTION_TEMPLATE_INSTANTIATION_LIMIT +# define SPROUT_RECURSIVE_FUNCTION_TEMPLATE_INSTANTIATION_LIMIT 512 +#endif + +// +// SPROUT_RECURSIVE_FUNCTION_TEMPLATE_CONTINUE_DECL +// SPROUT_RECURSIVE_FUNCTION_TEMPLATE_BREAK_DECL +// +#define SPROUT_RECURSIVE_FUNCTION_TEMPLATE_CONTINUE_DECL(depth) \ + typename sprout::enabler_if<((depth) < SPROUT_RECURSIVE_FUNCTION_TEMPLATE_INSTANTIATION_LIMIT - 1)>::type +#define SPROUT_RECURSIVE_FUNCTION_TEMPLATE_BREAK_DECL(depth) \ + typename sprout::enabler_if<((depth) >= SPROUT_RECURSIVE_FUNCTION_TEMPLATE_INSTANTIATION_LIMIT - 1)>::type + +// +// SPROUT_RECURSIVE_FUNCTION_TEMPLATE_CONTINUE +// SPROUT_RECURSIVE_FUNCTION_TEMPLATE_BREAK +// +#define SPROUT_RECURSIVE_FUNCTION_TEMPLATE_CONTINUE(depth) \ + SPROUT_RECURSIVE_FUNCTION_TEMPLATE_CONTINUE_DECL(depth) = sprout::enabler +#define SPROUT_RECURSIVE_FUNCTION_TEMPLATE_BREAK(depth) \ + SPROUT_RECURSIVE_FUNCTION_TEMPLATE_BREAK_DECL(depth) = sprout::enabler + +// +// SPROUT_RECURSIVE_FUNCTION_TEMPLATE_INSTANTIATION_EXCEEDED_MESSAGE +// +#define SPROUT_RECURSIVE_FUNCTION_TEMPLATE_INSTANTIATION_EXCEEDED_MESSAGE \ + "recursive template instantiation exceeded maximum depth of " SPROUT_PP_STRINGIZE(SPROUT_RECURSIVE_FUNCTION_TEMPLATE_INSTANTIATION_LIMIT) + +#endif // #ifndef SPROUT_WORKAROUND_RECURSIVE_FUNCTION_TEMPLATE_HPP