random_intersperse.hpp
Go to the documentation of this file.
1 // Copyright 2024 Ekumen, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef BELUGA_VIEWS_RANDOM_INTERSPERSE_HPP
16 #define BELUGA_VIEWS_RANDOM_INTERSPERSE_HPP
17 
18 #include <functional>
19 #include <optional>
20 #include <random>
21 #include <type_traits>
22 
23 #include <range/v3/functional/bind_back.hpp>
24 #include <range/v3/utility/random.hpp>
25 #include <range/v3/view/adaptor.hpp>
26 
32 namespace beluga::views {
33 
34 namespace detail {
35 
37 
44 template <class Range, class Fn, class URNG = typename ranges::detail::default_random_engine>
46  : public ranges::view_adaptor<
47  random_intersperse_view<Range, Fn, URNG>,
48  Range,
49  // The cardinality value is unknown at compile time.
50  // If the adapted range cardinality is finite then we know the resulting view is finite.
51  // But the intersperse probability could be 1.0, leading to an infinite range in practice.
52  ranges::unknown> {
53  public:
55  random_intersperse_view() = default;
56 
58 
65  Range range,
66  Fn fn,
67  double probability,
68  URNG& engine = ranges::detail::get_random_engine())
69  : random_intersperse_view::view_adaptor{std::move(range)},
70  fn_{std::move(fn)},
71  distribution_{probability},
72  engine_{std::addressof(engine)} {}
73 
74  private:
75  // `ranges::range_access` needs access to the adaptor members.
76  friend ranges::range_access;
77 
78  using result_type = ranges::common_type_t<decltype(std::declval<Fn>()()), ranges::range_value_t<Range>>;
79 
81  struct adaptor : public ranges::adaptor_base {
82  public:
84  adaptor() = default;
85 
87  constexpr explicit adaptor(random_intersperse_view* view) noexcept : view_(view) {}
88 
90  [[nodiscard]] constexpr auto read(ranges::iterator_t<Range> it) const { return fn_return_.value_or(*it); }
91 
93  constexpr void next(ranges::iterator_t<Range>& it) {
94  fn_return_.reset();
95  if (view_->should_intersperse()) {
96  fn_return_ = view_->fn_();
97  } else {
98  ++it;
99  }
100  }
101 
102  void prev(ranges::iterator_t<Range>& it) = delete;
103  void advance() = delete;
104  void distance_to() = delete;
105 
106  private:
108  std::optional<result_type> fn_return_;
109  };
110 
112  [[nodiscard]] constexpr auto begin_adaptor() { return adaptor{this}; }
113 
115  [[nodiscard]] constexpr bool should_intersperse() { return distribution_(*engine_); }
116 
117  ranges::semiregular_box_t<Fn> fn_;
118  std::bernoulli_distribution distribution_;
119  URNG* engine_;
120 };
121 
125  static constexpr double kDefaultProbability = 0.5;
126 
128 
139  template <class Range, class Fn, class URNG = typename ranges::detail::default_random_engine>
140  constexpr auto operator()(
141  Range&& range,
142  Fn fn,
143  double probability = kDefaultProbability,
144  URNG& engine = ranges::detail::get_random_engine()) const {
145  // Support nullary function objects and distribution-like objects (that take a URNG).
146  auto gen = [&fn, &engine]() {
147  if constexpr (std::is_invocable_v<Fn>) {
148  (void)(engine); // Not used.
149  return std::move(fn);
150  } else {
151  static_assert(std::is_invocable_v<Fn, decltype(engine)>);
152  return [fn = std::move(fn), &engine]() { return fn(engine); };
153  }
154  }();
155 
156  return random_intersperse_view{ranges::views::all(std::forward<Range>(range)), std::move(gen), probability, engine};
157  }
158 
160  template <class Range, class Fn, class URNG>
161  constexpr auto operator()(Range&& range, Fn fn, double probability, std::reference_wrapper<URNG> engine) const {
162  return (*this)(ranges::views::all(std::forward<Range>(range)), std::move(fn), probability, engine.get());
163  }
164 
166 
175  template <class Fn, class URNG = typename ranges::detail::default_random_engine>
176  constexpr auto operator()(
177  Fn fn,
178  double probability = kDefaultProbability,
179  URNG& engine = ranges::detail::get_random_engine()) const {
180  return ranges::make_view_closure(
181  ranges::bind_back(random_intersperse_fn{}, std::move(fn), probability, std::ref(engine)));
182  }
183 };
184 
185 } // namespace detail
186 
191 
192 } // namespace beluga::views
193 
194 #endif
beluga::views
Definition: elements.hpp:27
beluga::views::detail::random_intersperse_fn::kDefaultProbability
static constexpr double kDefaultProbability
Default insertion probability on each iteration.
Definition: random_intersperse.hpp:125
beluga::views::detail::random_intersperse_view::adaptor::adaptor
adaptor()=default
Default constructor.
beluga::views::detail::random_intersperse_view::fn_
ranges::semiregular_box_t< Fn > fn_
Definition: random_intersperse.hpp:117
beluga::views::detail::random_intersperse_view::adaptor::prev
void prev(ranges::iterator_t< Range > &it)=delete
beluga::views::detail::random_intersperse_view::adaptor::distance_to
void distance_to()=delete
beluga::views::detail::random_intersperse_view::adaptor::adaptor
constexpr adaptor(random_intersperse_view *view) noexcept
Construct an iterator adaptor from the parent view.
Definition: random_intersperse.hpp:87
beluga::views::detail::random_intersperse_fn
Implementation detail for a random_intersperse range adaptor object.
Definition: random_intersperse.hpp:123
beluga::views::detail::random_intersperse_view::should_intersperse
constexpr bool should_intersperse()
Return whether we should intersperse a value or increment the input iterator.
Definition: random_intersperse.hpp:115
beluga::views::detail::random_intersperse_view
Implementation of the random_intersperse view as a view adaptor.
Definition: random_intersperse.hpp:45
beluga::views::detail::random_intersperse_fn::operator()
constexpr auto operator()(Range &&range, Fn fn, double probability=kDefaultProbability, URNG &engine=ranges::detail::get_random_engine()) const
Overload that implements the andom_intersperse algorithm.
Definition: random_intersperse.hpp:140
beluga::views::detail::random_intersperse_fn::operator()
constexpr auto operator()(Range &&range, Fn fn, double probability, std::reference_wrapper< URNG > engine) const
Overload that unwraps the engine reference from a view closure.
Definition: random_intersperse.hpp:161
beluga::views::detail::random_intersperse_view::distribution_
std::bernoulli_distribution distribution_
Definition: random_intersperse.hpp:118
beluga::views::detail::random_intersperse_view::engine_
URNG * engine_
Definition: random_intersperse.hpp:119
beluga::views::detail::random_intersperse_view::adaptor::fn_return_
std::optional< result_type > fn_return_
Definition: random_intersperse.hpp:108
beluga::views::detail::random_intersperse_view::random_intersperse_view
random_intersperse_view()=default
Default constructor.
beluga::views::detail::random_intersperse_view::adaptor::read
constexpr auto read(ranges::iterator_t< Range > it) const
Return the inserted value or dereference the current iterator.
Definition: random_intersperse.hpp:90
beluga::views::detail::random_intersperse_view::adaptor::next
constexpr void next(ranges::iterator_t< Range > &it)
Generate a new value to be inserted or increment the input iterator.
Definition: random_intersperse.hpp:93
beluga::views::detail::random_intersperse_view::adaptor::view_
random_intersperse_view * view_
Definition: random_intersperse.hpp:107
beluga::views::random_intersperse
constexpr detail::random_intersperse_fn random_intersperse
Definition: random_intersperse.hpp:190
beluga::views::detail::random_intersperse_fn::operator()
constexpr auto operator()(Fn fn, double probability=kDefaultProbability, URNG &engine=ranges::detail::get_random_engine()) const
Overload that returns a view closure to compose with other views.
Definition: random_intersperse.hpp:176
beluga::views::detail::random_intersperse_view::random_intersperse_view
constexpr random_intersperse_view(Range range, Fn fn, double probability, URNG &engine=ranges::detail::get_random_engine())
Construct the view from a range to be adapted.
Definition: random_intersperse.hpp:64
beluga::views::detail::random_intersperse_view::adaptor::advance
void advance()=delete
beluga::views::detail::random_intersperse_view::begin_adaptor
constexpr auto begin_adaptor()
Return the adaptor for the begin iterator.
Definition: random_intersperse.hpp:112
beluga::views::detail::random_intersperse_view::result_type
ranges::common_type_t< decltype(std::declval< Fn >()()), ranges::range_value_t< Range > > result_type
Definition: random_intersperse.hpp:78
beluga::views::detail::random_intersperse_view::adaptor
Adaptor subclass that implements the random_intersperse logic.
Definition: random_intersperse.hpp:81


beluga
Author(s):
autogenerated on Tue Jul 16 2024 02:59:53