2 * Copyright 2017 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #ifndef FOLLY_GEN_CORE_H_
18 #error This file may only be included from folly/gen/Core.h
21 #include <type_traits>
24 // Ignore shadowing warnings within this file, so includers can use -Wshadow.
25 #pragma GCC diagnostic push
26 #pragma GCC diagnostic ignored "-Wshadow"
28 namespace folly { namespace gen {
31 * IsCompatibleSignature - Trait type for testing whether a given Functor
32 * matches an expected signature.
35 * IsCompatibleSignature<FunctorType, bool(int, float)>::value
37 template<class Candidate, class Expected>
38 class IsCompatibleSignature {
39 static constexpr bool value = false;
42 template<class Candidate,
45 class IsCompatibleSignature<Candidate, ExpectedReturn(ArgTypes...)> {
48 decltype(std::declval<F>()(std::declval<ArgTypes>()...)),
49 bool good = std::is_same<ExpectedReturn, ActualReturn>::value>
50 static constexpr bool testArgs(int*) {
55 static constexpr bool testArgs(...) {
59 static constexpr bool value = testArgs<Candidate>(nullptr);
63 * FBounded - Helper type for the curiously recurring template pattern, used
64 * heavily here to enable inlining and obviate virtual functions
68 const Self& self() const {
69 return *static_cast<const Self*>(this);
73 return *static_cast<Self*>(this);
78 * Operator - Core abstraction of an operation which may be applied to a
79 * generator. All operators implement a method compose(), which takes a
80 * generator and produces an output generator.
83 class Operator : public FBounded<Self> {
86 * compose() - Must be implemented by child class to compose a new Generator
87 * out of a given generator. This function left intentionally unimplemented.
89 template<class Source,
91 class ResultGen = void>
92 ResultGen compose(const GenImpl<Value, Source>& source) const;
96 Operator(Operator&&) noexcept = default;
97 Operator(const Operator&) = default;
98 Operator& operator=(Operator&&) noexcept = default;
99 Operator& operator=(const Operator&) = default;
103 * operator|() - For composing two operators without binding it to a
104 * particular generator.
108 class Composed = detail::Composed<Left, Right>>
109 Composed operator|(const Operator<Left>& left,
110 const Operator<Right>& right) {
111 return Composed(left.self(), right.self());
116 class Composed = detail::Composed<Left, Right>>
117 Composed operator|(const Operator<Left>& left,
118 Operator<Right>&& right) {
119 return Composed(left.self(), std::move(right.self()));
124 class Composed = detail::Composed<Left, Right>>
125 Composed operator|(Operator<Left>&& left,
126 const Operator<Right>& right) {
127 return Composed(std::move(left.self()), right.self());
132 class Composed = detail::Composed<Left, Right>>
133 Composed operator|(Operator<Left>&& left,
134 Operator<Right>&& right) {
135 return Composed(std::move(left.self()), std::move(right.self()));
139 * GenImpl - Core abstraction of a generator, an object which produces values by
140 * passing them to a given handler lambda. All generator implementations must
141 * implement apply(). foreach() may also be implemented to special case the
142 * condition where the entire sequence is consumed.
144 template<class Value,
146 class GenImpl : public FBounded<Self> {
148 // To prevent slicing
150 GenImpl(GenImpl&&) = default;
151 GenImpl(const GenImpl&) = default;
152 GenImpl& operator=(GenImpl&&) = default;
153 GenImpl& operator=(const GenImpl&) = default;
156 typedef Value ValueType;
157 typedef typename std::decay<Value>::type StorageType;
160 * apply() - Send all values produced by this generator to given handler until
161 * the handler returns false. Returns false if and only if the handler passed
162 * in returns false. Note: It should return true even if it completes (without
163 * the handler returning false), as 'Chain' uses the return value of apply to
164 * determine if it should process the second object in its chain.
166 template<class Handler>
167 bool apply(Handler&& handler) const;
170 * foreach() - Send all values produced by this generator to given lambda.
173 void foreach(Body&& body) const {
174 this->self().apply([&](Value value) -> bool {
175 static_assert(!infinite, "Cannot call foreach on infinite GenImpl");
176 body(std::forward<Value>(value));
181 // Child classes should override if the sequence generated is *definitely*
182 // infinite. 'infinite' may be false_type for some infinite sequences
183 // (due the the Halting Problem).
185 // In general, almost all sources are finite (only seq(n) produces an infinite
186 // source), almost all operators keep the finiteness of the source (only cycle
187 // makes an infinite generator from a finite one, only until and take make a
188 // finite generator from an infinite one, and concat needs both the inner and
189 // outer generators to be finite to make a finite one), and most sinks
190 // cannot accept and infinite generators (first being the expection).
191 static constexpr bool infinite = false;
194 template<class LeftValue,
198 class Chain = detail::Chain<LeftValue, Left, Right>>
199 Chain operator+(const GenImpl<LeftValue, Left>& left,
200 const GenImpl<RightValue, Right>& right) {
202 std::is_same<LeftValue, RightValue>::value,
203 "Generators may ony be combined if Values are the exact same type.");
204 return Chain(left.self(), right.self());
207 template<class LeftValue,
211 class Chain = detail::Chain<LeftValue, Left, Right>>
212 Chain operator+(const GenImpl<LeftValue, Left>& left,
213 GenImpl<RightValue, Right>&& right) {
215 std::is_same<LeftValue, RightValue>::value,
216 "Generators may ony be combined if Values are the exact same type.");
217 return Chain(left.self(), std::move(right.self()));
220 template<class LeftValue,
224 class Chain = detail::Chain<LeftValue, Left, Right>>
225 Chain operator+(GenImpl<LeftValue, Left>&& left,
226 const GenImpl<RightValue, Right>& right) {
228 std::is_same<LeftValue, RightValue>::value,
229 "Generators may ony be combined if Values are the exact same type.");
230 return Chain(std::move(left.self()), right.self());
233 template<class LeftValue,
237 class Chain = detail::Chain<LeftValue, Left, Right>>
238 Chain operator+(GenImpl<LeftValue, Left>&& left,
239 GenImpl<RightValue, Right>&& right) {
241 std::is_same<LeftValue, RightValue>::value,
242 "Generators may ony be combined if Values are the exact same type.");
243 return Chain(std::move(left.self()), std::move(right.self()));
247 * operator|() which enables foreach-like usage:
248 * gen | [](Value v) -> void {...};
250 template<class Value,
253 typename std::enable_if<
254 IsCompatibleSignature<Handler, void(Value)>::value>::type
255 operator|(const GenImpl<Value, Gen>& gen, Handler&& handler) {
256 static_assert(!Gen::infinite,
257 "Cannot pull all values from an infinite sequence.");
258 gen.self().foreach(std::forward<Handler>(handler));
262 * operator|() which enables foreach-like usage with 'break' support:
263 * gen | [](Value v) -> bool { return shouldContinue(); };
265 template<class Value,
268 typename std::enable_if<
269 IsCompatibleSignature<Handler, bool(Value)>::value, bool>::type
270 operator|(const GenImpl<Value, Gen>& gen, Handler&& handler) {
271 return gen.self().apply(std::forward<Handler>(handler));
275 * operator|() for composing generators with operators, similar to boosts' range
277 * gen | map(square) | sum
279 template<class Value,
282 auto operator|(const GenImpl<Value, Gen>& gen, const Operator<Op>& op) ->
283 decltype(op.self().compose(gen.self())) {
284 return op.self().compose(gen.self());
287 template<class Value,
290 auto operator|(GenImpl<Value, Gen>&& gen, const Operator<Op>& op) ->
291 decltype(op.self().compose(std::move(gen.self()))) {
292 return op.self().compose(std::move(gen.self()));
298 * Composed - For building up a pipeline of operations to perform, absent any
299 * particular source generator. Useful for building up custom pipelines.
301 * This type is usually used by just piping two operators together:
303 * auto valuesOf = filter([](Optional<int>& o) { return o.hasValue(); })
304 * | map([](Optional<int>& o) -> int& { return o.value(); });
306 * auto valuesIncluded = from(optionals) | valuesOf | as<vector>();
308 template<class First,
310 class Composed : public Operator<Composed<First, Second>> {
314 Composed() = default;
316 Composed(First first, Second second)
317 : first_(std::move(first))
318 , second_(std::move(second)) {}
320 template<class Source,
322 class FirstRet = decltype(std::declval<First>()
323 .compose(std::declval<Source>())),
324 class SecondRet = decltype(std::declval<Second>()
325 .compose(std::declval<FirstRet>()))>
326 SecondRet compose(const GenImpl<Value, Source>& source) const {
327 return second_.compose(first_.compose(source.self()));
330 template<class Source,
332 class FirstRet = decltype(std::declval<First>()
333 .compose(std::declval<Source>())),
334 class SecondRet = decltype(std::declval<Second>()
335 .compose(std::declval<FirstRet>()))>
336 SecondRet compose(GenImpl<Value, Source>&& source) const {
337 return second_.compose(first_.compose(std::move(source.self())));
342 * Chain - For concatenating the values produced by two Generators.
344 * This type is primarily used through using '+' to combine generators, like:
346 * auto nums = seq(1, 10) + seq(20, 30);
347 * int total = nums | sum;
349 template<class Value, class First, class Second>
350 class Chain : public GenImpl<Value,
351 Chain<Value, First, Second>> {
355 explicit Chain(First first, Second second)
356 : first_(std::move(first))
357 , second_(std::move(second)) {}
359 template<class Handler>
360 bool apply(Handler&& handler) const {
361 return first_.apply(std::forward<Handler>(handler))
362 && second_.apply(std::forward<Handler>(handler));
366 void foreach(Body&& body) const {
367 first_.foreach(std::forward<Body>(body));
368 second_.foreach(std::forward<Body>(body));
371 static constexpr bool infinite = First::infinite || Second::infinite;
378 #pragma GCC diagnostic pop