15 #ifndef BELUGA_VIEWS_SAMPLE_HPP
16 #define BELUGA_VIEWS_SAMPLE_HPP
20 #include <range/v3/utility/random.hpp>
21 #include <range/v3/view/common.hpp>
22 #include <range/v3/view/generate.hpp>
46 template <
class Range,
class Distribution,
class URNG =
typename ranges::detail::default_random_engine>
47 struct sample_view :
public ranges::view_facade<sample_view<Range, Distribution, URNG>, ranges::infinite> {
58 constexpr
sample_view(Range range, Distribution distribution, URNG& engine = ranges::detail::get_random_engine())
60 assert(ranges::size(range) > 0);
62 assert(
distribution_.max() ==
static_cast<typename Distribution::result_type
>(ranges::size(
range_)) - 1);
67 friend ranges::range_access;
69 static_assert(ranges::sized_range<Range>);
70 static_assert(ranges::random_access_range<Range>);
71 static_assert(std::is_same_v<
typename Distribution::result_type, ranges::range_difference_t<Range>>);
84 [[nodiscard]] constexpr decltype(
auto)
read() const noexcept(noexcept(*this->
it_)) {
return *
it_; }
92 ranges::iterator_t<Range>
it_;
99 [[nodiscard]] constexpr
auto end_cursor() const noexcept {
return ranges::unreachable_sentinel_t{}; }
111 template <
class T,
class Enable =
void>
112 struct is_random_distribution :
public std::false_type {};
115 struct is_random_distribution<T,
std::void_t<decltype(std::declval<T&>()(std::declval<std::mt19937&>()))>>
119 inline constexpr
bool is_random_distribution_v = is_random_distribution<T>::value;
127 template <
class Range,
class Weights,
class URNG>
129 static_assert(ranges::sized_range<Range>);
130 static_assert(ranges::random_access_range<Range>);
131 static_assert(ranges::input_range<Weights>);
132 using result_type = ranges::range_difference_t<Range>;
133 auto w = ranges::views::common(
weights);
134 auto distribution = std::discrete_distribution<result_type>{ranges::begin(w), ranges::end(w)};
135 return sample_view{ranges::views::all(std::forward<Range>(range)), std::move(distribution), engine};
146 template <
class Range,
class URNG>
148 static_assert(ranges::sized_range<Range>);
149 static_assert(ranges::random_access_range<Range>);
150 if constexpr (beluga::is_particle_range_v<Range>) {
154 using result_type = ranges::range_difference_t<Range>;
156 std::uniform_int_distribution<result_type>{0,
static_cast<result_type
>(ranges::size(range) - 1)};
157 return sample_view{ranges::views::all(std::forward<Range>(range)), std::move(distribution), engine};
162 template <
class Distribution,
class URNG>
164 return ranges::views::generate(
165 [distribution = std::move(distribution), &engine]()
mutable {
return distribution(engine); });
172 template <
class T,
class U,
class V>
174 static_assert(ranges::range<T>);
175 static_assert(ranges::range<U>);
180 template <
class T,
class U>
182 if constexpr (ranges::range<T> && ranges::range<U>) {
183 auto& engine = ranges::detail::get_random_engine();
185 }
else if constexpr (is_random_distribution_v<T>) {
186 static_assert(std::is_lvalue_reference_v<U&&>);
189 static_assert(ranges::range<T>);
190 static_assert(std::is_lvalue_reference_v<U&&>);
198 if constexpr (ranges::range<T>) {
199 auto& engine = ranges::detail::get_random_engine();
201 }
else if constexpr (is_random_distribution_v<T>) {
202 auto& engine = ranges::detail::get_random_engine();
205 static_assert(std::is_lvalue_reference_v<T&&>);
206 return ranges::make_view_closure(ranges::bind_back(
sample_fn{}, std::ref(t)));
211 template <
class Range,
class URNG>
212 constexpr
auto operator()(Range&& range, std::reference_wrapper<URNG> engine)
const {
213 static_assert(ranges::range<Range>);
240 inline constexpr ranges::views::view_closure<detail::sample_fn>
sample;