#ifndef SPROUT_RANDOM_RANDOM_ITERATOR_HPP #define SPROUT_RANDOM_RANDOM_ITERATOR_HPP #include #include #include #include #include #include #include #include namespace sprout { namespace random { // // random_iterator // template class random_iterator; template class random_iterator< Engine, Distribution, typename std::enable_if::value>::type > : public std::iterator< typename std::iterator_traits >::iterator_category, typename std::iterator_traits >::value_type, typename std::iterator_traits >::difference_type, typename std::iterator_traits >::pointer, typename std::iterator_traits >::reference > { public: typedef sprout::random::random_result random_result_type; typedef typename random_result_type::engine_type engine_type; typedef typename random_result_type::distribution_type distribution_type; typedef typename random_result_type::result_type result_type; typedef typename std::iterator_traits::iterator_category iterator_category; typedef typename std::iterator_traits::value_type value_type; typedef typename std::iterator_traits::difference_type difference_type; typedef typename std::iterator_traits::pointer pointer; typedef typename std::iterator_traits::reference reference; private: random_result_type random_; difference_type count_; public: SPROUT_CONSTEXPR random_iterator() : random_() , count_() {} SPROUT_CONSTEXPR random_iterator( engine_type const& engine, distribution_type const& distribution, difference_type count = -1 ) : random_(distribution(engine)) , count_(count) {} explicit SPROUT_CONSTEXPR random_iterator( random_result_type const& random, difference_type count = -1 ) : random_(random) , count_(count) {} SPROUT_CONSTEXPR random_iterator operator()() const { return count_ != 0 ? random_iterator(random_(), count_ > 0 ? count_ - 1 : count_) : throw std::out_of_range("random_iterator<>: increment at out of range") ; } random_result_type& random_result() { return random_; } SPROUT_CONSTEXPR random_result_type const& random_result() const { return random_; } result_type& result() { return random_.result(); } SPROUT_CONSTEXPR result_type const& result() const { return random_.result(); } engine_type& engine() { return random_.engine(); } SPROUT_CONSTEXPR engine_type const& engine() const { return random_.engine(); } distribution_type& distribution() { return random_.distribution(); } SPROUT_CONSTEXPR distribution_type const& distribution() const { return random_.distribution(); } SPROUT_CONSTEXPR result_type min() const { return random_.min(); } SPROUT_CONSTEXPR result_type max() const { return random_.max(); } SPROUT_CONSTEXPR result_type count() const { return count_; } void swap(random_iterator& other) { using std::swap; swap(random_, other.random_); swap(count_, other.count_); } friend SPROUT_CONSTEXPR bool operator==(random_iterator const& lhs, random_iterator const& rhs) { return lhs.count_ == rhs.count_ && (lhs.count_ == 0 || lhs.random_ == rhs.random_); } friend SPROUT_CONSTEXPR bool operator!=(random_iterator const& lhs, random_iterator const& rhs) { return !(lhs == rhs); } SPROUT_CONSTEXPR reference operator*() const { return count_ != 0 ? random_.result() : (throw std::out_of_range("random_iterator<>: dereference at out of range"), random_.result()) ; } SPROUT_CONSTEXPR pointer operator->() const { return count_ != 0 ? &random_.result() : throw std::out_of_range("random_iterator<>: dereference at out of range") ; } random_iterator& operator++() { random_iterator temp((*this)()); temp.swap(*this); return *this; } random_iterator operator++(int) { random_iterator result(*this); ++*this; return result; } }; template class random_iterator< Engine, Distribution, typename std::enable_if::value>::type > : public std::iterator< typename std::iterator_traits >::iterator_category, typename std::iterator_traits >::value_type, typename std::iterator_traits >::difference_type, typename std::iterator_traits >::pointer, typename std::iterator_traits >::reference > { public: typedef sprout::random::random_result random_result_type; typedef typename random_result_type::engine_type engine_type; typedef typename random_result_type::result_type result_type; typedef typename std::iterator_traits::iterator_category iterator_category; typedef typename std::iterator_traits::value_type value_type; typedef typename std::iterator_traits::difference_type difference_type; typedef typename std::iterator_traits::pointer pointer; typedef typename std::iterator_traits::reference reference; private: random_result_type random_; difference_type count_; public: SPROUT_CONSTEXPR random_iterator() : random_() , count_() {} SPROUT_CONSTEXPR random_iterator( engine_type const& engine, difference_type count = -1 ) : random_(engine()) , count_(count) {} explicit SPROUT_CONSTEXPR random_iterator( random_result_type const& random, difference_type count = -1 ) : random_(random) , count_(count) {} SPROUT_CONSTEXPR random_iterator operator()() const { return count_ != 0 ? random_iterator(random_(), count_ > 0 ? count_ - 1 : count_) : throw std::out_of_range("random_iterator<>: increment at out of range") ; } random_result_type& random_result() { return random_; } SPROUT_CONSTEXPR random_result_type const& random_result() const { return random_; } result_type& result() { return random_.result(); } SPROUT_CONSTEXPR result_type const& result() const { return random_.result(); } engine_type& engine() { return random_.engine(); } SPROUT_CONSTEXPR engine_type const& engine() const { return random_.engine(); } SPROUT_CONSTEXPR result_type min() const { return random_.min(); } SPROUT_CONSTEXPR result_type max() const { return random_.max(); } SPROUT_CONSTEXPR result_type count() const { return count_; } void swap(random_iterator& other) { using std::swap; swap(random_, other.random_); swap(count_, other.count_); } friend SPROUT_CONSTEXPR bool operator==(random_iterator const& lhs, random_iterator const& rhs) { return lhs.count_ == rhs.count_ && (lhs.count_ == 0 || lhs.random_ == rhs.random_); } friend SPROUT_CONSTEXPR bool operator!=(random_iterator const& lhs, random_iterator const& rhs) { return !(lhs == rhs); } SPROUT_CONSTEXPR reference operator*() const { return count_ != 0 ? random_.result() : (throw std::out_of_range("random_iterator<>: dereference at out of range"), random_.result()) ; } SPROUT_CONSTEXPR pointer operator->() const { return count_ > 0 ? &random_.result() : throw std::out_of_range("random_iterator<>: dereference at out of range") ; } random_iterator& operator++() { random_iterator temp((*this)()); temp.swap(*this); return *this; } random_iterator operator++(int) { random_iterator result(*this); ++*this; return result; } }; // // swap // template void swap( sprout::random::random_iterator& lhs, sprout::random::random_iterator& rhs ) { lhs.swap(rhs); } // // begin // template SPROUT_CONSTEXPR typename std::enable_if< !std::is_integral::value, sprout::random::random_iterator >::type begin( Engine const& engine, Distribution const& distribution, typename sprout::random::random_iterator::difference_type count = -1 ) { return sprout::random::random_iterator(engine, distribution, count); } template SPROUT_CONSTEXPR sprout::random::random_iterator begin( Engine const& engine, typename sprout::random::random_iterator::difference_type count = -1 ) { return sprout::random::random_iterator(engine, count); } // // end // template SPROUT_CONSTEXPR sprout::random::random_iterator end( Engine const& engine, Distribution const& distribution ) { return sprout::random::random_iterator(); } template SPROUT_CONSTEXPR sprout::random::random_iterator end( Engine const& engine ) { return sprout::random::random_iterator(); } // // next // template SPROUT_CONSTEXPR sprout::random::random_iterator next( sprout::random::random_iterator const& it ) { return it(); } } // namespace random using sprout::random::random_iterator; } // namespace sprout #endif // #ifndef SPROUT_RANDOM_RANDOM_ITERATOR_HPP