2 * Copyright 2014 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 // Ignore shadowing warnings within this file, so includers can use -Wshadow.
22 #pragma GCC diagnostic push
23 #pragma GCC diagnostic ignored "-Wshadow"
25 namespace folly { namespace gen {
28 * IsCompatibleSignature - Trait type for testing whether a given Functor
29 * matches an expected signature.
32 * IsCompatibleSignature<FunctorType, bool(int, float)>::value
34 template<class Candidate, class Expected>
35 class IsCompatibleSignature {
36 static constexpr bool value = false;
39 template<class Candidate,
42 class IsCompatibleSignature<Candidate, ExpectedReturn(ArgTypes...)> {
45 decltype(std::declval<F>()(std::declval<ArgTypes>()...)),
46 bool good = std::is_same<ExpectedReturn, ActualReturn>::value>
47 static constexpr bool testArgs(int* p) {
52 static constexpr bool testArgs(...) {
56 static constexpr bool value = testArgs<Candidate>(nullptr);
60 * FBounded - Helper type for the curiously recurring template pattern, used
61 * heavily here to enable inlining and obviate virtual functions
65 const Self& self() const {
66 return *static_cast<const Self*>(this);
70 return *static_cast<Self*>(this);
75 * Operator - Core abstraction of an operation which may be applied to a
76 * generator. All operators implement a method compose(), which takes a
77 * generator and produces an output generator.
80 class Operator : public FBounded<Self> {
83 * compose() - Must be implemented by child class to compose a new Generator
84 * out of a given generator. This function left intentionally unimplemented.
86 template<class Source,
88 class ResultGen = void>
89 ResultGen compose(const GenImpl<Value, Source>& source) const;
93 Operator(const Operator&) = default;
94 Operator(Operator&&) = default;
98 * operator|() - For composing two operators without binding it to a
99 * particular generator.
103 class Composed = detail::Composed<Left, Right>>
104 Composed operator|(const Operator<Left>& left,
105 const Operator<Right>& right) {
106 return Composed(left.self(), right.self());
111 class Composed = detail::Composed<Left, Right>>
112 Composed operator|(const Operator<Left>& left,
113 Operator<Right>&& right) {
114 return Composed(left.self(), std::move(right.self()));
119 class Composed = detail::Composed<Left, Right>>
120 Composed operator|(Operator<Left>&& left,
121 const Operator<Right>& right) {
122 return Composed(std::move(left.self()), right.self());
127 class Composed = detail::Composed<Left, Right>>
128 Composed operator|(Operator<Left>&& left,
129 Operator<Right>&& right) {
130 return Composed(std::move(left.self()), std::move(right.self()));
134 * GenImpl - Core abstraction of a generator, an object which produces values by
135 * passing them to a given handler lambda. All generator implementations must
136 * implement apply(). foreach() may also be implemented to special case the
137 * condition where the entire sequence is consumed.
139 template<class Value,
141 class GenImpl : public FBounded<Self> {
143 // To prevent slicing
145 GenImpl(const GenImpl&) = default;
146 GenImpl(GenImpl&&) = default;
149 typedef Value ValueType;
150 typedef typename std::decay<Value>::type StorageType;
153 * apply() - Send all values produced by this generator to given handler until
154 * the handler returns false. Returns false if and only if the handler passed
155 * in returns false. Note: It should return true even if it completes (without
156 * the handler returning false), as 'Chain' uses the return value of apply to
157 * determine if it should process the second object in its chain.
159 template<class Handler>
160 bool apply(Handler&& handler) const;
163 * foreach() - Send all values produced by this generator to given lambda.
166 void foreach(Body&& body) const {
167 this->self().apply([&](Value value) -> bool {
168 static_assert(!infinite, "Cannot call foreach on infinite GenImpl");
169 body(std::forward<Value>(value));
174 // Child classes should override if the sequence generated is *definitely*
175 // infinite. 'infinite' may be false_type for some infinite sequences
176 // (due the the Halting Problem).
177 static constexpr bool infinite = false;
180 template<class LeftValue,
184 class Chain = detail::Chain<LeftValue, Left, Right>>
185 Chain operator+(const GenImpl<LeftValue, Left>& left,
186 const GenImpl<RightValue, Right>& right) {
188 std::is_same<LeftValue, RightValue>::value,
189 "Generators may ony be combined if Values are the exact same type.");
190 return Chain(left.self(), right.self());
193 template<class LeftValue,
197 class Chain = detail::Chain<LeftValue, Left, Right>>
198 Chain operator+(const GenImpl<LeftValue, Left>& left,
199 GenImpl<RightValue, Right>&& right) {
201 std::is_same<LeftValue, RightValue>::value,
202 "Generators may ony be combined if Values are the exact same type.");
203 return Chain(left.self(), std::move(right.self()));
206 template<class LeftValue,
210 class Chain = detail::Chain<LeftValue, Left, Right>>
211 Chain operator+(GenImpl<LeftValue, Left>&& left,
212 const GenImpl<RightValue, Right>& right) {
214 std::is_same<LeftValue, RightValue>::value,
215 "Generators may ony be combined if Values are the exact same type.");
216 return Chain(std::move(left.self()), right.self());
219 template<class LeftValue,
223 class Chain = detail::Chain<LeftValue, Left, Right>>
224 Chain operator+(GenImpl<LeftValue, Left>&& left,
225 GenImpl<RightValue, Right>&& right) {
227 std::is_same<LeftValue, RightValue>::value,
228 "Generators may ony be combined if Values are the exact same type.");
229 return Chain(std::move(left.self()), std::move(right.self()));
233 * operator|() which enables foreach-like usage:
234 * gen | [](Value v) -> void {...};
236 template<class Value,
239 typename std::enable_if<
240 IsCompatibleSignature<Handler, void(Value)>::value>::type
241 operator|(const GenImpl<Value, Gen>& gen, Handler&& handler) {
242 static_assert(!Gen::infinite,
243 "Cannot pull all values from an infinite sequence.");
244 gen.self().foreach(std::forward<Handler>(handler));
248 * operator|() which enables foreach-like usage with 'break' support:
249 * gen | [](Value v) -> bool { return shouldContinue(); };
251 template<class Value,
254 typename std::enable_if<
255 IsCompatibleSignature<Handler, bool(Value)>::value, bool>::type
256 operator|(const GenImpl<Value, Gen>& gen, Handler&& handler) {
257 return gen.self().apply(std::forward<Handler>(handler));
261 * operator|() for composing generators with operators, similar to boosts' range
263 * gen | map(square) | sum
265 template<class Value,
268 auto operator|(const GenImpl<Value, Gen>& gen, const Operator<Op>& op) ->
269 decltype(op.self().compose(gen.self())) {
270 return op.self().compose(gen.self());
273 template<class Value,
276 auto operator|(GenImpl<Value, Gen>&& gen, const Operator<Op>& op) ->
277 decltype(op.self().compose(std::move(gen.self()))) {
278 return op.self().compose(std::move(gen.self()));
284 * Composed - For building up a pipeline of operations to perform, absent any
285 * particular source generator. Useful for building up custom pipelines.
287 * This type is usually used by just piping two operators together:
289 * auto valuesOf = filter([](Optional<int>& o) { return o.hasValue(); })
290 * | map([](Optional<int>& o) -> int& { return o.value(); });
292 * auto valuesIncluded = from(optionals) | valuesOf | as<vector>();
294 template<class First,
296 class Composed : public Operator<Composed<First, Second>> {
302 Composed(First first, Second second)
303 : first_(std::move(first))
304 , second_(std::move(second)) {}
306 template<class Source,
308 class FirstRet = decltype(std::declval<First>()
309 .compose(std::declval<Source>())),
310 class SecondRet = decltype(std::declval<Second>()
311 .compose(std::declval<FirstRet>()))>
312 SecondRet compose(const GenImpl<Value, Source>& source) const {
313 return second_.compose(first_.compose(source.self()));
316 template<class Source,
318 class FirstRet = decltype(std::declval<First>()
319 .compose(std::declval<Source>())),
320 class SecondRet = decltype(std::declval<Second>()
321 .compose(std::declval<FirstRet>()))>
322 SecondRet compose(GenImpl<Value, Source>&& source) const {
323 return second_.compose(first_.compose(std::move(source.self())));
328 * Chain - For concatenating the values produced by two Generators.
330 * This type is primarily used through using '+' to combine generators, like:
332 * auto nums = seq(1, 10) + seq(20, 30);
333 * int total = nums | sum;
335 template<class Value, class First, class Second>
336 class Chain : public GenImpl<Value,
337 Chain<Value, First, Second>> {
341 explicit Chain(First first, Second second)
342 : first_(std::move(first))
343 , second_(std::move(second)) {}
345 template<class Handler>
346 bool apply(Handler&& handler) const {
347 return first_.apply(std::forward<Handler>(handler))
348 && second_.apply(std::forward<Handler>(handler));
352 void foreach(Body&& body) const {
353 first_.foreach(std::forward<Body>(body));
354 second_.foreach(std::forward<Body>(body));
357 static constexpr bool infinite = First::infinite || Second::infinite;
364 #pragma GCC diagnostic pop