folly/folly/gen/Core-inl.h

/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef FOLLY_GEN_CORE_H_
#error This file may only be included from folly/gen/Core.h
#endif

#include <type_traits>
#include <utility>

#include <folly/Portability.h>

// Ignore shadowing warnings within this file, so includers can use -Wshadow.
FOLLY_PUSH_WARNING
FOLLY_GNU_DISABLE_WARNING()

namespace folly {
namespace gen {

/**
 * IsCompatibleSignature - Trait type for testing whether a given Functor
 * matches an expected signature.
 *
 * Usage:
 *   IsCompatibleSignature<FunctorType, bool(int, float)>::value
 */
template <class Candidate, class Expected>
class IsCompatibleSignature {};

IsCompatibleSignature<Candidate, ExpectedReturn (ArgTypes...)>;

/**
 * FBounded - Helper type for the curiously recurring template pattern, used
 * heavily here to enable inlining and obviate virtual functions
 */
template <class Self>
struct FBounded {};

/**
 * Operator - Core abstraction of an operation which may be applied to a
 * generator. All operators implement a method compose(), which takes a
 * generator and produces an output generator.
 */
template <class Self>
class Operator : public FBounded<Self> {};

/**
 * operator|() - For composing two operators without binding it to a
 * particular generator.
 */
template <
    class Left,
    class Right,
    class Composed = detail::Composed<Left, Right>>
Composed operator|(const Operator<Left>& left, const Operator<Right>& right) {}

template <
    class Left,
    class Right,
    class Composed = detail::Composed<Left, Right>>
Composed operator|(const Operator<Left>& left, Operator<Right>&& right) {}

template <
    class Left,
    class Right,
    class Composed = detail::Composed<Left, Right>>
Composed operator|(Operator<Left>&& left, const Operator<Right>& right) {}

template <
    class Left,
    class Right,
    class Composed = detail::Composed<Left, Right>>
Composed operator|(Operator<Left>&& left, Operator<Right>&& right) {}

/**
 * GenImpl - Core abstraction of a generator, an object which produces values by
 * passing them to a given handler lambda. All generator implementations must
 * implement apply(). foreach() may also be implemented to special case the
 * condition where the entire sequence is consumed.
 */
template <class Value, class Self>
class GenImpl : public FBounded<Self> {};

template <
    class LeftValue,
    class Left,
    class RightValue,
    class Right,
    class Chain = detail::Chain<LeftValue, Left, Right>>
Chain operator+(
    const GenImpl<LeftValue, Left>& left,
    const GenImpl<RightValue, Right>& right) {}

template <
    class LeftValue,
    class Left,
    class RightValue,
    class Right,
    class Chain = detail::Chain<LeftValue, Left, Right>>
Chain operator+(
    const GenImpl<LeftValue, Left>& left, GenImpl<RightValue, Right>&& right) {}

template <
    class LeftValue,
    class Left,
    class RightValue,
    class Right,
    class Chain = detail::Chain<LeftValue, Left, Right>>
Chain operator+(
    GenImpl<LeftValue, Left>&& left, const GenImpl<RightValue, Right>& right) {}

template <
    class LeftValue,
    class Left,
    class RightValue,
    class Right,
    class Chain = detail::Chain<LeftValue, Left, Right>>
Chain operator+(
    GenImpl<LeftValue, Left>&& left, GenImpl<RightValue, Right>&& right) {}

/**
 * operator|() which enables foreach-like usage:
 *   gen | [](Value v) -> void {...};
 */
template <class Value, class Gen, class Handler>
typename std::enable_if<
    IsCompatibleSignature<Handler, void(Value)>::value>::type
operator|(const GenImpl<Value, Gen>& gen, Handler&& handler) {}

/**
 * operator|() which enables foreach-like usage with 'break' support:
 *   gen | [](Value v) -> bool { return shouldContinue(); };
 */
template <class Value, class Gen, class Handler>
typename std::
    enable_if<IsCompatibleSignature<Handler, bool(Value)>::value, bool>::type
    operator|(const GenImpl<Value, Gen>& gen, Handler&& handler) {}

/**
 * operator|() for composing generators with operators, similar to boosts' range
 * adaptors:
 *   gen | map(square) | sum
 */
template <class Value, class Gen, class Op>
auto operator|(const GenImpl<Value, Gen>& gen, const Operator<Op>& op)
    -> decltype(op.self().compose(gen.self())) {}

template <class Value, class Gen, class Op>
auto operator|(GenImpl<Value, Gen>&& gen, const Operator<Op>& op)
    -> decltype(op.self().compose(std::move(gen.self()))) {}

namespace detail {

/**
 * Composed - For building up a pipeline of operations to perform, absent any
 * particular source generator. Useful for building up custom pipelines.
 *
 * This type is usually used by just piping two operators together:
 *
 * auto valuesOf = filter([](Optional<int>& o) { return o.hasValue(); })
 *               | map([](Optional<int>& o) -> int& { return o.value(); });
 *
 *  auto valuesIncluded = from(optionals) | valuesOf | as<vector>();
 */
template <class First, class Second>
class Composed : public Operator<Composed<First, Second>> {};

/**
 * Chain - For concatenating the values produced by two Generators.
 *
 * This type is primarily used through using '+' to combine generators, like:
 *
 *   auto nums = seq(1, 10) + seq(20, 30);
 *   int total = nums | sum;
 */
template <class Value, class First, class Second>
class Chain : public GenImpl<Value, Chain<Value, First, Second>> {};

} // namespace detail
} // namespace gen
} // namespace folly

FOLLY_POP_WARNING