/*============================================================================= Copyright (c) 2011-2019 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_RANDOM_RANDOM_RESULT_HPP #define SPROUT_RANDOM_RANDOM_RESULT_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace sprout { namespace random { // // random_result // template class random_result< Engine, Distribution, typename std::enable_if::value>::type > : public sprout::iterator< std::input_iterator_tag, typename std::remove_reference::type::result_type, std::ptrdiff_t, typename std::remove_reference::type::result_type const*, typename std::remove_reference::type::result_type const& > { public: typedef Engine engine_type; typedef Distribution distribution_type; typedef typename std::remove_reference::type::result_type result_type; typedef sprout::random::variate_generator generator_type; private: typedef sprout::iterator< std::input_iterator_tag, result_type, std::ptrdiff_t, result_type const*, result_type const& > base_type; typedef sprout::random::detail::ptr_helper engine_helper_type; typedef sprout::random::detail::ptr_helper distribution_helper_type; public: typedef typename base_type::iterator_category iterator_category; typedef typename base_type::value_type value_type; typedef typename base_type::difference_type difference_type; typedef typename base_type::pointer pointer; typedef typename base_type::reference reference; typedef typename engine_helper_type::value_type engine_value_type; typedef typename distribution_helper_type::value_type distribution_value_type; typedef typename engine_helper_type::reference_type engine_reference_type; typedef typename distribution_helper_type::reference_type distribution_reference_type; typedef typename engine_helper_type::const_reference_type engine_const_reference_type; typedef typename distribution_helper_type::const_reference_type distribution_const_reference_type; typedef typename engine_helper_type::rvalue_type engine_param_type; typedef typename distribution_helper_type::rvalue_type distribution_param_type; typedef typename generator_type::random_result_type random_result_type; private: result_type result_; generator_type generator_; public: SPROUT_CONSTEXPR random_result() : result_(), generator_() {} random_result(random_result const&) = default; SPROUT_CONSTEXPR random_result( result_type const& result, engine_param_type engine, distribution_param_type distribution ) : result_(result) , generator_(engine, distribution) {} SPROUT_CONSTEXPR random_result_type operator()() const { return generator_(); } SPROUT_CXX14_CONSTEXPR result_type& generated_value() SPROUT_NOEXCEPT { return result_; } SPROUT_CONSTEXPR result_type const& generated_value() const SPROUT_NOEXCEPT { return result_; } SPROUT_CXX14_CONSTEXPR generator_type& next_generator() SPROUT_NOEXCEPT { return generator_; } SPROUT_CONSTEXPR generator_type const& next_generator() const SPROUT_NOEXCEPT { return generator_; } SPROUT_CONSTEXPR random_result_type next_value() const SPROUT_NOEXCEPT { return generator_(); } SPROUT_CXX14_CONSTEXPR result_type& result() SPROUT_NOEXCEPT { return result_; } SPROUT_CONSTEXPR result_type const& result() const SPROUT_NOEXCEPT { return result_; } SPROUT_CXX14_CONSTEXPR generator_type& next() SPROUT_NOEXCEPT { return generator_; } SPROUT_CONSTEXPR generator_type const& next() const SPROUT_NOEXCEPT { return generator_; } SPROUT_CXX14_CONSTEXPR engine_reference_type engine() SPROUT_NOEXCEPT { return generator_.engine(); } SPROUT_CONSTEXPR engine_const_reference_type engine() const SPROUT_NOEXCEPT { return generator_.engine(); } SPROUT_CXX14_CONSTEXPR distribution_reference_type distribution() SPROUT_NOEXCEPT { return generator_.distribution(); } SPROUT_CONSTEXPR distribution_const_reference_type distribution() const SPROUT_NOEXCEPT { return generator_.distribution(); } SPROUT_CXX14_CONSTEXPR operator result_type&() SPROUT_NOEXCEPT { return result_; } SPROUT_CONSTEXPR operator result_type const&() const SPROUT_NOEXCEPT { return result_; } SPROUT_CONSTEXPR result_type min() const SPROUT_NOEXCEPT { return distribution().min(); } SPROUT_CONSTEXPR result_type max() const SPROUT_NOEXCEPT { return distribution().max(); } SPROUT_CXX14_CONSTEXPR void swap(random_result& other) SPROUT_NOEXCEPT_IF( SPROUT_NOEXCEPT_EXPR(sprout::swap(result_, other.result_)) && SPROUT_NOEXCEPT_EXPR(sprout::swap(generator_, other.generator_)) ) { sprout::swap(result_, other.result_); sprout::swap(generator_, other.generator_); } friend SPROUT_CONSTEXPR bool operator==(random_result const& lhs, random_result const& rhs) SPROUT_NOEXCEPT { return lhs.result_ == rhs.result_ && lhs.generator_ == rhs.generator_ ; } friend SPROUT_CONSTEXPR bool operator!=(random_result const& lhs, random_result const& rhs) SPROUT_NOEXCEPT { return !(lhs == rhs); } SPROUT_CONSTEXPR reference operator*() const SPROUT_NOEXCEPT { return result_; } SPROUT_CONSTEXPR pointer operator->() const SPROUT_NOEXCEPT { return &result_; } SPROUT_CXX14_CONSTEXPR random_result& operator++() { random_result temp((*this)()); temp.swap(*this); return *this; } SPROUT_CXX14_CONSTEXPR random_result operator++(int) { random_result result(*this); ++*this; return result; } }; template class random_result< Engine, Distribution, typename std::enable_if::value>::type > : public sprout::iterator< std::input_iterator_tag, typename std::remove_reference::type::result_type, std::ptrdiff_t, typename std::remove_reference::type::result_type const*, typename std::remove_reference::type::result_type const& > { public: typedef Engine engine_type; typedef typename std::remove_reference::type::result_type result_type; typedef engine_type generator_type; private: typedef sprout::iterator< std::input_iterator_tag, result_type, std::ptrdiff_t, result_type const*, result_type const& > base_type; typedef sprout::random::detail::ptr_helper engine_helper_type; public: typedef typename base_type::iterator_category iterator_category; typedef typename base_type::value_type value_type; typedef typename base_type::difference_type difference_type; typedef typename base_type::pointer pointer; typedef typename base_type::reference reference; typedef typename engine_helper_type::value_type engine_value_type; typedef typename engine_helper_type::reference_type engine_reference_type; typedef typename engine_helper_type::const_reference_type engine_const_reference_type; typedef typename engine_helper_type::rvalue_type engine_param_type; typedef random_result random_result_type; private: result_type result_; generator_type generator_; public: SPROUT_CONSTEXPR random_result() : result_(), generator_() {} random_result(random_result const&) = default; SPROUT_CONSTEXPR random_result(result_type result, engine_param_type engine) : result_(result), generator_(engine) {} SPROUT_CONSTEXPR random_result_type operator()() const { return generator_(); } SPROUT_CXX14_CONSTEXPR result_type& generated_value() SPROUT_NOEXCEPT { return result_; } SPROUT_CONSTEXPR result_type const& generated_value() const SPROUT_NOEXCEPT { return result_; } SPROUT_CXX14_CONSTEXPR generator_type& next_generator() SPROUT_NOEXCEPT { return generator_; } SPROUT_CONSTEXPR generator_type const& next_generator() const SPROUT_NOEXCEPT { return generator_; } SPROUT_CONSTEXPR random_result_type next_value() const SPROUT_NOEXCEPT { return generator_(); } SPROUT_CXX14_CONSTEXPR result_type& result() SPROUT_NOEXCEPT { return result_; } SPROUT_CONSTEXPR result_type const& result() const SPROUT_NOEXCEPT { return result_; } SPROUT_CXX14_CONSTEXPR generator_type& next() SPROUT_NOEXCEPT { return generator_; } SPROUT_CONSTEXPR generator_type const& next() const SPROUT_NOEXCEPT { return generator_; } SPROUT_CXX14_CONSTEXPR engine_reference_type engine() SPROUT_NOEXCEPT { return generator_; } SPROUT_CONSTEXPR engine_const_reference_type engine() const SPROUT_NOEXCEPT { return generator_; } SPROUT_CXX14_CONSTEXPR operator result_type&() SPROUT_NOEXCEPT { return result_; } SPROUT_CONSTEXPR operator result_type const&() const SPROUT_NOEXCEPT { return result_; } SPROUT_CONSTEXPR result_type min() const SPROUT_NOEXCEPT { return engine().min(); } SPROUT_CONSTEXPR result_type max() const SPROUT_NOEXCEPT { return engine().max(); } friend SPROUT_CONSTEXPR bool operator==(random_result const& lhs, random_result const& rhs) SPROUT_NOEXCEPT { return lhs.result_ == rhs.result_ && lhs.generator_ == rhs.generator_ ; } friend SPROUT_CONSTEXPR bool operator!=(random_result const& lhs, random_result const& rhs) SPROUT_NOEXCEPT { return !(lhs == rhs); } SPROUT_CXX14_CONSTEXPR void swap(random_result& other) SPROUT_NOEXCEPT_IF( SPROUT_NOEXCEPT_EXPR(sprout::swap(result_, other.result_)) && SPROUT_NOEXCEPT_EXPR(sprout::swap(generator_, other.generator_)) ) { sprout::swap(result_, other.result_); sprout::swap(generator_, other.generator_); } SPROUT_CONSTEXPR reference operator*() const SPROUT_NOEXCEPT { return result_; } SPROUT_CONSTEXPR pointer operator->() const SPROUT_NOEXCEPT { return &result_; } SPROUT_CXX14_CONSTEXPR random_result& operator++() { random_result temp((*this)()); temp.swap(*this); return *this; } SPROUT_CXX14_CONSTEXPR random_result operator++(int) { random_result result(*this); random_result temp((*this)()); temp.swap(*this); return result; } }; // // swap // template inline SPROUT_CXX14_CONSTEXPR void swap(sprout::random::random_result& lhs, sprout::random::random_result& rhs) SPROUT_NOEXCEPT_IF_EXPR(lhs.swap(rhs)) { lhs.swap(rhs); } // // iterator_next // template inline SPROUT_CONSTEXPR sprout::random::random_result iterator_next(sprout::random::random_result const& it) { return it(); } } // namespace random namespace tuples { namespace detail { template struct tuple_element_impl; template struct tuple_element_impl > : public sprout::detail::nil_base {}; template struct tuple_element_impl<0, sprout::random::random_result > : public sprout::identity::result_type> {}; template struct tuple_element_impl<1, sprout::random::random_result > : public sprout::identity::generator_type> {}; template struct get_impl; template struct get_impl<0, sprout::random::random_result > { public: SPROUT_CONSTEXPR typename sprout::random::random_result::result_type& operator()(sprout::random::random_result& t) const { return t.generated_value(); } SPROUT_CONSTEXPR typename sprout::random::random_result::result_type const& operator()(sprout::random::random_result const& t) const { return t.generated_value(); } }; template struct get_impl<1, sprout::random::random_result > { public: SPROUT_CONSTEXPR typename sprout::random::random_result::generator_type& operator()(sprout::random::random_result& t) const { return t.next_generator(); } SPROUT_CONSTEXPR typename sprout::random::random_result::generator_type const& operator()(sprout::random::random_result const& t) const { return t.next_generator(); } }; } // namespace detail } // namespace tuples } // namespace sprout namespace std { #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wmismatched-tags" #endif // // tuple_size // template struct tuple_size > : public sprout::integral_constant {}; // // tuple_element // template struct tuple_element > : public sprout::tuples::detail::tuple_element_impl > {}; #if defined(__clang__) # pragma clang diagnostic pop #endif } // namespace std namespace sprout { namespace random { // // tuple_get // template inline SPROUT_CONSTEXPR typename sprout::tuples::tuple_element >::type& tuple_get(sprout::random::random_result& t) SPROUT_NOEXCEPT { static_assert(I < 2, "tuple_get: index out of range"); return sprout::tuples::detail::get_impl >()(t); } template inline SPROUT_CONSTEXPR typename sprout::tuples::tuple_element >::type const& tuple_get(sprout::random::random_result const& t) SPROUT_NOEXCEPT { static_assert(I < 2, "tuple_get: index out of range"); return sprout::tuples::detail::get_impl >()(t); } template inline SPROUT_CONSTEXPR typename sprout::tuples::tuple_element >::type&& tuple_get(sprout::random::random_result&& t) SPROUT_NOEXCEPT { return sprout::move(sprout::tuples::get(t)); } } // namespace random } // namespace sprout #endif // #ifndef SPROUT_RANDOM_RANDOM_RESULT_HPP