folly/folly/functional/traits.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.
 */

#pragma once

#include <folly/Traits.h>

namespace folly {

namespace detail {

template <typename>
struct function_traits_base_;

function_traits_base_<R (A...)>;

template <bool Nx>
struct function_traits_nx_ {};

template <bool Var>
struct function_traits_var_ {};

template <typename T>
struct function_traits_cvref_ {};

} // namespace detail

//  function_traits
//
//  Incomplete except when instantiated over any type matching std::is_function.
//  Namely, types S over R, A..., NX of the form:
//
//      S = R(A...) [const] [volatile] (|&|&&) noexcept(NX)
//
//  When complete, has a class body of the form:
//
//      struct function_traits<S> {
//        using result_type = R;
//        static constexpr bool is_nothrow = NX;
//
//        template <std::size_t Index>
//        using argument = type_pack_element_t<Index, A...>;
//        template <typename F>
//        using arguments = F<A...>;
//        template <typename Model>
//        using value_like = Model [const] [volatile] (|&|&&);
//      };
//
//  Member argument is a metafunction allowing access to one argument type at a
//  time, by positional index:
//
//      using second_argument_type = function_traits<S>::argument<1>;
//
//  Member arguments is a metafunction allowing access to all argument types at
//  once:
//
//      using arguments_tuple_type =
//          function_traits<S>::arguments<std::tuple>;
//
//  Member value_like is a metafunction allowing access to the const-,
//  volatile-, and reference-qualifiers using like_t to transport all these
//  qualifiers to a destination type which may then be queried:
//
//      constexpr bool is_rvalue_reference = std::is_rvalue_reverence_v<
//          function_traits<S>::value_like<int>>;
//
//  Keep in mind that member types or type-aliases must be referenced with
//  keyword typename when dependent and that member templates must likewise be
//  referenced with keyword template when in dependent:
//
//      template <typename... A>
//      using get_size = index_constant<sizeof...(A);
//      template <typename S>
//      using arguments_size_t =
//          typename function_traits<S>::template arguments<get_size>;
//
//  Every fact of a function type S is thus discoverable from function_traits<S>
//  without requiring further class template specializations or further overload
//  set searches, all as types or constexpr values.
//
//  Further specializations are forbidden.
template <typename>
struct function_traits;

function_traits<R (A...)>;

function_traits<R (A...) const>;

function_traits<R (A...) volatile>;

function_traits<R (A...) const volatile>;

function_traits<R (A...) &>;

function_traits<R (A...) const &>;

function_traits<R (A...) volatile &>;

function_traits<R (A...) const volatile &>;

function_traits<R (A...) &&>;

function_traits<R (A...) const &&>;

function_traits<R (A...) volatile &&>;

function_traits<R (A...) const volatile &&>;

function_traits<R (A..., ...)>;

function_traits<R (A..., ...) const>;

function_traits<R (A..., ...) volatile>;

function_traits<R (A..., ...) const volatile>;

function_traits<R (A..., ...) &>;

function_traits<R (A..., ...) const &>;

function_traits<R (A..., ...) volatile &>;

function_traits<R (A..., ...) const volatile &>;

function_traits<R (A..., ...) &&>;

function_traits<R (A..., ...) const &&>;

function_traits<R (A..., ...) volatile &&>;

function_traits<R (A..., ...) const volatile &&>;

function_traits<R (A...) noexcept>;

function_traits<R (A...) const noexcept>;

function_traits<R (A...) volatile noexcept>;

function_traits<R (A...) const volatile noexcept>;

function_traits<R (A...) & noexcept>;

function_traits<R (A...) const & noexcept>;

function_traits<R (A...) volatile & noexcept>;

function_traits<R (A...) const volatile & noexcept>;

function_traits<R (A...) && noexcept>;

function_traits<R (A...) const && noexcept>;

function_traits<R (A...) volatile && noexcept>;

function_traits<R (A...) const volatile && noexcept>;

function_traits<R (A..., ...) noexcept>;

function_traits<R (A..., ...) const noexcept>;

function_traits<R (A..., ...) volatile noexcept>;

function_traits<R (A..., ...) const volatile noexcept>;

function_traits<R (A..., ...) & noexcept>;

function_traits<R (A..., ...) const & noexcept>;

function_traits<R (A..., ...) volatile & noexcept>;

function_traits<R (A..., ...) const volatile & noexcept>;

function_traits<R (A..., ...) && noexcept>;

function_traits<R (A..., ...) const && noexcept>;

function_traits<R (A..., ...) volatile && noexcept>;

function_traits<R (A..., ...) const volatile && noexcept>;

//  ----

namespace detail {

template <bool Nx, bool Var, typename R>
struct function_remove_cvref_;
function_remove_cvref_<false, false, R>;
function_remove_cvref_<false, true, R>;
function_remove_cvref_<true, false, R>;
function_remove_cvref_<true, true, R>;

function_remove_cvref_t_;

} // namespace detail

//  function_remove_cvref
//  function_remove_cvref_t
//
//  Given a function type of the form:
//      S = R(A...) [const] [volatile] (|&|&&) noexcept(NX)
//  Yields another function type:
//      R(A...) noexcept(NX)

function_remove_cvref_t;

template <typename F>
struct function_remove_cvref {};

//  ----

namespace detail {

template <typename Src, bool Var>
struct function_like_src_;
function_like_src_<Src, 0>;
function_like_src_<const Src, 0>;
function_like_src_<volatile Src, 0>;
function_like_src_<const volatile Src, 0>;
function_like_src_<Src &, 0>;
function_like_src_<const Src &, 0>;
function_like_src_<volatile Src &, 0>;
function_like_src_<const volatile Src &, 0>;
function_like_src_<Src &&, 0>;
function_like_src_<const Src &&, 0>;
function_like_src_<volatile Src &&, 0>;
function_like_src_<const volatile Src &&, 0>;
function_like_src_<Src, 1>;
function_like_src_<const Src, 1>;
function_like_src_<volatile Src, 1>;
function_like_src_<const volatile Src, 1>;
function_like_src_<Src &, 1>;
function_like_src_<const Src &, 1>;
function_like_src_<volatile Src &, 1>;
function_like_src_<const volatile Src &, 1>;
function_like_src_<Src &&, 1>;
function_like_src_<const Src &&, 1>;
function_like_src_<volatile Src &&, 1>;
function_like_src_<const volatile Src &&, 1>;

template <typename Dst>
struct function_like_dst_ : function_like_dst_<function_remove_cvref_t<Dst>> {};
function_like_dst_<R (A...)>;
function_like_dst_<R (A..., ...)>;
function_like_dst_<R (A...) noexcept>;
function_like_dst_<R (A..., ...) noexcept>;

} // namespace detail

//  function_like_value
//  function_like_value_t
//
//  Given a possibly-cvref-qualified value type Src and a possibly-cvref-
//  qualified function type Dst,  transports any cvref-qualifications found on
//  Src onto the base function type of Dst, which is Dst stripped of its own
//  cvref-qualifications.
//
//  Example:
//      function_like_value_t<int volatile, void() const&&> -> void() volatile
//      function_like_value_t<int const&&, void() volatile> -> void() const&&

function_like_value_t;

template <typename Src, typename Dst>
struct function_like_value {};

} // namespace folly