blob: 572f7a33faca5af480741e6672d86d16b93d71d6 [file] [log] [blame] [edit]
// Copyright 2026 The Abseil Authors.
//
// 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
//
// https://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 ABSL_EXTEND_INTERNAL_DEPENDENCIES_H_
#define ABSL_EXTEND_INTERNAL_DEPENDENCIES_H_
#include <type_traits>
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace dependencies_internal {
// Dependencies is a meta-function which constructs a collection which
// recursively looks through types and either adds them to the list, or, if they
// have a `using deps = void(...);` takes those listed dependencies as well. For
// example, given:
//
// struct X {};
// struct Y {};
// struct A {};
// struct B { using deps = void(A, X); };
// struct C { using deps = void(A, Y); };
// struct D { using deps = void(B, C); };
//
// Dependencies<D>() will return a function pointer returning void and accepting
// arguments of types A, B, C, D, X, and Y in some unspecified order each
// exactly once, and no other types.
template <typename T>
auto GetDependencies(T*) -> typename T::deps*;
auto GetDependencies(void*) -> void (*)();
template <typename FnPtr, typename... Ts>
struct CombineDeps {};
template <typename... Ps, typename... Ts>
struct CombineDeps<void (*)(Ps...), Ts...> {
using type = void (*)(Ps..., Ts...);
};
template <typename... Processed>
auto DependenciesImpl(void (*)(), void (*)(Processed...)) {
return static_cast<void (*)(Processed...)>(nullptr);
}
template <typename T, typename... Ts, typename... Processed>
auto DependenciesImpl(void (*)(T, Ts...), void (*)(Processed...)) {
if constexpr ((std::is_same_v<T, Processed> || ...)) {
return DependenciesImpl(static_cast<void (*)(Ts...)>(nullptr),
static_cast<void (*)(Processed...)>(nullptr));
} else {
using deps = decltype(GetDependencies(static_cast<T*>(nullptr)));
if constexpr (std ::is_same_v<deps, void (*)()>) {
return DependenciesImpl(static_cast<void (*)(Ts...)>(nullptr),
static_cast<void (*)(T, Processed...)>(nullptr));
} else {
return DependenciesImpl(
static_cast<typename CombineDeps<deps, Ts...>::type>(nullptr),
static_cast<void (*)(T, Processed...)>(nullptr));
}
}
}
template <typename... Ts>
using Dependencies = decltype(DependenciesImpl(
static_cast<void (*)(Ts...)>(nullptr), static_cast<void (*)()>(nullptr)));
} // namespace dependencies_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_EXTEND_INTERNAL_DEPENDENCIES_H_