| // Copyright 2019 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_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_ |
| #define ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_ |
| |
| // Checks to determine whether or not we can use abi::__cxa_demangle |
| #if (defined(__ANDROID__) || defined(ANDROID)) && !defined(OS_ANDROID) |
| #define ABSL_INTERNAL_OS_ANDROID |
| #endif |
| |
| // We support certain compilers only. See demangle.h for details. |
| #if defined(OS_ANDROID) && (defined(__i386__) || defined(__x86_64__)) |
| #define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 0 |
| #elif (__GNUC__ >= 4 || (__GNUC__ >= 3 && __GNUC_MINOR__ >= 4)) && \ |
| !defined(__mips__) |
| #define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 1 |
| #elif defined(__clang__) && !defined(_MSC_VER) |
| #define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 1 |
| #else |
| #define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 0 |
| #endif |
| |
| #include <tuple> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/meta/type_traits.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/utility/utility.h" |
| |
| #if ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE |
| #include <cxxabi.h> |
| |
| #include <cstdlib> |
| #endif |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace types_internal { |
| |
| // Return a readable name for type T. |
| template <class T> |
| absl::string_view NameOfImpl() { |
| // TODO(calabrese) Investigate using debugging:internal_demangle as a fallback. |
| #if ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE |
| int status = 0; |
| char* demangled_name = nullptr; |
| |
| demangled_name = |
| abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status); |
| |
| if (status == 0 && demangled_name != nullptr) { |
| return demangled_name; |
| } else { |
| return typeid(T).name(); |
| } |
| #else |
| return typeid(T).name(); |
| #endif |
| // NOTE: We intentionally leak demangled_name so that it remains valid |
| // throughout the remainder of the program. |
| } |
| |
| // Given a type, returns as nice of a type name as we can produce (demangled). |
| // |
| // Note: This currently strips cv-qualifiers and references, but that is okay |
| // because we only use this internally with unqualified object types. |
| template <class T> |
| std::string NameOf() { |
| static const absl::string_view result = NameOfImpl<T>(); |
| return std::string(result); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Metafunction to check if a type is callable with no explicit arguments |
| template <class Fun, class /*Enabler*/ = void> |
| struct IsNullaryCallableImpl : std::false_type {}; |
| |
| template <class Fun> |
| struct IsNullaryCallableImpl< |
| Fun, absl::void_t<decltype(std::declval<const Fun&>()())>> |
| : std::true_type { |
| using result_type = decltype(std::declval<const Fun&>()()); |
| |
| template <class ValueType> |
| using for_type = std::is_same<ValueType, result_type>; |
| |
| using void_if_true = void; |
| }; |
| |
| template <class Fun> |
| struct IsNullaryCallable : IsNullaryCallableImpl<Fun> {}; |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // A type that contains a function object that returns an instance of a type |
| // that is undergoing conformance testing. This function is required to always |
| // return the same value upon invocation. |
| template <class Fun> |
| struct GeneratorType; |
| |
| // A type that contains a tuple of GeneratorType<Fun> where each Fun has the |
| // same return type. The result of each of the different generators should all |
| // be equal values, though the underlying object representation may differ (such |
| // as if one returns 0.0 and another return -0.0, or if one returns an empty |
| // vector and another returns an empty vector with a different capacity. |
| template <class... Funs> |
| struct EquivalenceClassType; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // A metafunction to check if a type is a specialization of EquivalenceClassType |
| template <class T> |
| struct IsEquivalenceClass : std::false_type {}; |
| |
| template <> |
| struct IsEquivalenceClass<EquivalenceClassType<>> : std::true_type { |
| using self = IsEquivalenceClass; |
| |
| // A metafunction to check if this EquivalenceClassType is a valid |
| // EquivalenceClassType for a type `ValueType` that is undergoing testing |
| template <class ValueType> |
| using for_type = std::true_type; |
| }; |
| |
| template <class Head, class... Tail> |
| struct IsEquivalenceClass<EquivalenceClassType<Head, Tail...>> |
| : std::true_type { |
| using self = IsEquivalenceClass; |
| |
| // The type undergoing conformance testing that this EquivalenceClass |
| // corresponds to |
| using result_type = typename IsNullaryCallable<Head>::result_type; |
| |
| // A metafunction to check if this EquivalenceClassType is a valid |
| // EquivalenceClassType for a type `ValueType` that is undergoing testing |
| template <class ValueType> |
| using for_type = std::is_same<ValueType, result_type>; |
| }; |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // A type that contains an ordered series of EquivalenceClassTypes, where the |
| // the function object of each underlying GeneratorType has the same return type |
| // |
| // These equivalence classes are required to be in a logical ascending order |
| // that is consistent with comparison operators that are defined for the return |
| // type of each GeneratorType, if any. |
| template <class... EqClasses> |
| struct OrderedEquivalenceClasses; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // A metafunction to determine the return type of the function object contained |
| // in a GeneratorType specialization. |
| template <class T> |
| struct ResultOfGenerator {}; |
| |
| template <class Fun> |
| struct ResultOfGenerator<GeneratorType<Fun>> { |
| using type = decltype(std::declval<const Fun&>()()); |
| }; |
| |
| template <class Fun> |
| using ResultOfGeneratorT = typename ResultOfGenerator<GeneratorType<Fun>>::type; |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // A metafunction that yields true iff each of Funs is a GeneratorType |
| // specialization and they all contain functions with the same return type |
| template <class /*Enabler*/, class... Funs> |
| struct AreGeneratorsWithTheSameReturnTypeImpl : std::false_type {}; |
| |
| template <> |
| struct AreGeneratorsWithTheSameReturnTypeImpl<void> : std::true_type {}; |
| |
| template <class Head, class... Tail> |
| struct AreGeneratorsWithTheSameReturnTypeImpl< |
| typename std::enable_if<absl::conjunction<std::is_same< |
| ResultOfGeneratorT<Head>, ResultOfGeneratorT<Tail>>...>::value>::type, |
| Head, Tail...> : std::true_type {}; |
| |
| template <class... Funs> |
| struct AreGeneratorsWithTheSameReturnType |
| : AreGeneratorsWithTheSameReturnTypeImpl<void, Funs...>::type {}; |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // A metafunction that yields true iff each of Funs is an EquivalenceClassType |
| // specialization and they all contain GeneratorType specializations that have |
| // the same return type |
| template <class... EqClasses> |
| struct AreEquivalenceClassesOfTheSameType { |
| static_assert(sizeof...(EqClasses) != sizeof...(EqClasses), ""); |
| }; |
| |
| template <> |
| struct AreEquivalenceClassesOfTheSameType<> : std::true_type { |
| using self = AreEquivalenceClassesOfTheSameType; |
| |
| // Metafunction to check that a type is the same as all of the equivalence |
| // classes, if any. |
| // Note: In this specialization there are no equivalence classes, so the |
| // value type is always compatible. |
| template <class /*ValueType*/> |
| using for_type = std::true_type; |
| }; |
| |
| template <class... Funs> |
| struct AreEquivalenceClassesOfTheSameType<EquivalenceClassType<Funs...>> |
| : std::true_type { |
| using self = AreEquivalenceClassesOfTheSameType; |
| |
| // Metafunction to check that a type is the same as all of the equivalence |
| // classes, if any. |
| template <class ValueType> |
| using for_type = typename IsEquivalenceClass< |
| EquivalenceClassType<Funs...>>::template for_type<ValueType>; |
| }; |
| |
| template <class... TailEqClasses> |
| struct AreEquivalenceClassesOfTheSameType< |
| EquivalenceClassType<>, EquivalenceClassType<>, TailEqClasses...> |
| : AreEquivalenceClassesOfTheSameType<TailEqClasses...>::self {}; |
| |
| template <class HeadNextFun, class... TailNextFuns, class... TailEqClasses> |
| struct AreEquivalenceClassesOfTheSameType< |
| EquivalenceClassType<>, EquivalenceClassType<HeadNextFun, TailNextFuns...>, |
| TailEqClasses...> |
| : AreEquivalenceClassesOfTheSameType< |
| EquivalenceClassType<HeadNextFun, TailNextFuns...>, |
| TailEqClasses...>::self {}; |
| |
| template <class HeadHeadFun, class... TailHeadFuns, class... TailEqClasses> |
| struct AreEquivalenceClassesOfTheSameType< |
| EquivalenceClassType<HeadHeadFun, TailHeadFuns...>, EquivalenceClassType<>, |
| TailEqClasses...> |
| : AreEquivalenceClassesOfTheSameType< |
| EquivalenceClassType<HeadHeadFun, TailHeadFuns...>, |
| TailEqClasses...>::self {}; |
| |
| template <class HeadHeadFun, class... TailHeadFuns, class HeadNextFun, |
| class... TailNextFuns, class... TailEqClasses> |
| struct AreEquivalenceClassesOfTheSameType< |
| EquivalenceClassType<HeadHeadFun, TailHeadFuns...>, |
| EquivalenceClassType<HeadNextFun, TailNextFuns...>, TailEqClasses...> |
| : absl::conditional_t< |
| IsNullaryCallable<HeadNextFun>::template for_type< |
| typename IsNullaryCallable<HeadHeadFun>::result_type>::value, |
| AreEquivalenceClassesOfTheSameType< |
| EquivalenceClassType<HeadHeadFun, TailHeadFuns...>, |
| TailEqClasses...>, |
| std::false_type> {}; |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // Execute a function for each passed-in parameter. |
| template <class Fun, class... Cases> |
| void ForEachParameter(const Fun& fun, const Cases&... cases) { |
| const std::initializer_list<bool> results = { |
| (static_cast<void>(fun(cases)), true)...}; |
| |
| (void)results; |
| } |
| |
| // Execute a function on each passed-in parameter (using a bound function). |
| template <class Fun> |
| struct ForEachParameterFun { |
| template <class... T> |
| void operator()(const T&... cases) const { |
| (ForEachParameter)(fun, cases...); |
| } |
| |
| Fun fun; |
| }; |
| |
| // Execute a function on each element of a tuple. |
| template <class Fun, class Tup> |
| void ForEachTupleElement(const Fun& fun, const Tup& tup) { |
| absl::apply(ForEachParameterFun<Fun>{fun}, tup); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Execute a function for each combination of two elements of a tuple, including |
| // combinations of an element with itself. |
| template <class Fun, class... T> |
| struct ForEveryTwoImpl { |
| template <class Lhs> |
| struct WithBoundLhs { |
| template <class Rhs> |
| void operator()(const Rhs& rhs) const { |
| fun(lhs, rhs); |
| } |
| |
| Fun fun; |
| Lhs lhs; |
| }; |
| |
| template <class Lhs> |
| void operator()(const Lhs& lhs) const { |
| (ForEachTupleElement)(WithBoundLhs<Lhs>{fun, lhs}, args); |
| } |
| |
| Fun fun; |
| std::tuple<T...> args; |
| }; |
| |
| template <class Fun, class... T> |
| void ForEveryTwo(const Fun& fun, std::tuple<T...> args) { |
| (ForEachTupleElement)(ForEveryTwoImpl<Fun, T...>{fun, args}, args); |
| } |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Insert all values into an associative container |
| template<class Container> |
| void InsertEach(Container* cont) { |
| } |
| |
| template<class Container, class H, class... T> |
| void InsertEach(Container* cont, H&& head, T&&... tail) { |
| cont->insert(head); |
| (InsertEach)(cont, tail...); |
| } |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| // A template with a nested "Invoke" static-member-function that executes a |
| // passed-in Callable when `Condition` is true, otherwise it ignores the |
| // Callable. This is useful for executing a function object with a condition |
| // that corresponds to whether or not the Callable can be safely instantiated. |
| // It has some overlapping uses with C++17 `if constexpr`. |
| template <bool Condition> |
| struct If; |
| |
| template <> |
| struct If</*Condition =*/false> { |
| template <class Fun, class... P> |
| static void Invoke(const Fun& /*fun*/, P&&... /*args*/) {} |
| }; |
| |
| template <> |
| struct If</*Condition =*/true> { |
| template <class Fun, class... P> |
| static void Invoke(const Fun& fun, P&&... args) { |
| // TODO(calabrese) Use std::invoke equivalent instead of function-call. |
| fun(absl::forward<P>(args)...); |
| } |
| }; |
| |
| // |
| // ABSL_INTERNAL_STRINGIZE(...) |
| // |
| // This variadic macro transforms its arguments into a c-string literal after |
| // expansion. |
| // |
| // Example: |
| // |
| // ABSL_INTERNAL_STRINGIZE(std::array<int, 10>) |
| // |
| // Results in: |
| // |
| // "std::array<int, 10>" |
| #define ABSL_INTERNAL_STRINGIZE(...) ABSL_INTERNAL_STRINGIZE_IMPL((__VA_ARGS__)) |
| #define ABSL_INTERNAL_STRINGIZE_IMPL(arg) ABSL_INTERNAL_STRINGIZE_IMPL2 arg |
| #define ABSL_INTERNAL_STRINGIZE_IMPL2(...) #__VA_ARGS__ |
| |
| } // namespace types_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_ |