| // Copyright 2022 Google LLC |
| // |
| // 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 FUZZTEST_FUZZTEST_INTERNAL_META_H_ |
| #define FUZZTEST_FUZZTEST_INTERNAL_META_H_ |
| |
| #include <array> |
| #include <cstddef> |
| #include <cstdlib> |
| #include <memory> |
| #include <optional> |
| #include <ostream> |
| #include <tuple> |
| #include <type_traits> |
| #include <utility> |
| #include <variant> |
| |
| #include "absl/numeric/int128.h" |
| |
| namespace google::protobuf { |
| template <typename T> |
| struct is_proto_enum; |
| } // namespace google::protobuf |
| |
| namespace fuzztest::internal { |
| |
| template <size_t... I, typename F> |
| constexpr auto ApplyIndexImpl(F f, std::index_sequence<I...>) { |
| return f(std::integral_constant<size_t, I>{}...); |
| } |
| |
| // Invoke `f(std::integral_constant<size_t, 0>{}, ..., |
| // std::integral_constant<size_t, N - 1>{}); |
| // |
| // Useful with a generic lambda like: |
| // ApplyIndex<N>([&](auto... I) { |
| // (std::get<I>(....), ...); |
| // } |
| // This allows users to expand an N without needing their own helper |
| // function/specialization generally required when working with |
| // std::index_sequence. |
| template <size_t N, typename F> |
| constexpr auto ApplyIndex(F f) { |
| return ApplyIndexImpl(f, std::make_index_sequence<N>{}); |
| } |
| |
| // Calls f(std::integral_constant<size_t, i>{}). |
| // Requires `0 <= i && i < Max` |
| // This function raises a runtime int into a static int. Useful for dealing with |
| // tuples, variants, etc. |
| template <size_t Max, typename F> |
| decltype(auto) Switch(size_t i, F f) { |
| using Call = decltype(f(std::integral_constant<size_t, 0>())) (*)(F&); |
| return ApplyIndex<Max>([](auto... I) { |
| static constexpr Call kFuncs[] = { |
| [](F& f) { return std::move(f)(decltype(I){}); }...}; |
| return kFuncs; |
| })[i](f); |
| } |
| |
| // Type dependent "true"/"false". |
| // Useful for SFINAE and static_asserts where we need a type dependent |
| // expression that happens to be constant. |
| template <typename T> |
| constexpr std::false_type always_false = {}; |
| template <typename T> |
| constexpr std::true_type always_true = {}; |
| |
| // "backport" of C++20's `requires` expression. |
| // It can be used as: |
| // if constexpr (Requires<T>([](auto x) -> decltype(x.foo()) {})) { |
| // with similar behavior as C++20's |
| // if constexpr (requires{ t.foo(); }) { |
| // Much more verbose than `requires`, but still much more compact than the |
| // SFINAE alternative. |
| template <typename... T, typename F> |
| constexpr bool Requires(F) { |
| return std::is_invocable_v<F, T...>; |
| } |
| |
| // Simple typeid implementation that does not require RTTI. |
| // Only supports comparisons for equality. |
| using TypeId = const void*; |
| template <typename T> |
| inline constexpr TypeId type_id = &type_id<T>; |
| |
| // Some simple type traits |
| template <typename T> |
| inline constexpr bool is_monostate_v = std::is_class_v<T>&& std::is_empty_v<T>&& |
| std::is_default_constructible_v<T>; |
| |
| template <typename T> |
| inline constexpr bool is_variant_v = false; |
| |
| template <typename... T> |
| inline constexpr bool is_variant_v<std::variant<T...>> = true; |
| |
| template <typename T> |
| inline constexpr bool is_pair_v = false; |
| |
| template <typename T, typename U> |
| inline constexpr bool is_pair_v<std::pair<T, U>> = true; |
| |
| template <typename... T> |
| inline constexpr bool is_tuple_v = false; |
| |
| template <typename... T> |
| inline constexpr bool is_tuple_v<std::tuple<T...>> = true; |
| |
| template <typename T> |
| inline constexpr bool is_array_v = false; |
| |
| template <typename T, size_t N> |
| inline constexpr bool is_array_v<std::array<T, N>> = true; |
| |
| template <typename T> |
| inline constexpr bool is_bitvector_v = false; |
| |
| template <> |
| inline constexpr bool is_bitvector_v<std::vector<bool>> = true; |
| |
| template <typename T> |
| inline constexpr bool is_vector_v = false; |
| |
| template <typename T> |
| inline constexpr bool is_vector_v<std::vector<T>> = true; |
| |
| template <typename T> |
| inline constexpr bool is_unique_ptr_v = false; |
| |
| template <typename T> |
| inline constexpr bool is_unique_ptr_v<std::unique_ptr<T>> = true; |
| |
| template <typename T> |
| inline constexpr bool is_shared_ptr_v = false; |
| |
| template <typename T> |
| inline constexpr bool is_shared_ptr_v<std::shared_ptr<T>> = true; |
| |
| template <typename T> |
| using MakeUnsignedT = typename std::conditional_t< |
| std::is_same_v<T, absl::int128> || std::is_same_v<T, absl::uint128>, |
| std::enable_if<true, absl::uint128>, std::make_unsigned<T>>::type; |
| |
| // Protocol buffers are handled through duck typing to avoid a strong dependency |
| // on the library. |
| template <typename T> |
| constexpr bool IsProtocolBufferImpl(typename T::Message*) { |
| // Check the basics: |
| // - There is a base class called Message. |
| // - It has GetReflection/GetDescriptor methods. |
| // - They interact as we expect with each other. |
| // |
| // We can add more specifics if this is still too ambiguous. |
| using Message = typename T::Message; |
| return std::is_base_of_v<Message, T> && |
| std::is_convertible_v<const T*, const Message*> && |
| Requires<const Message*>( |
| [](auto* f) -> decltype(f->GetReflection()->HasField( |
| *f, f->GetDescriptor()->field(0))) {}); |
| } |
| |
| template <typename T> |
| constexpr bool IsProtocolBufferImpl(...) { |
| return false; |
| } |
| |
| template <typename T> |
| inline constexpr bool is_protocol_buffer_v = IsProtocolBufferImpl<T>(nullptr); |
| |
| template <typename T> |
| constexpr bool IsProtocolBufferEnumImpl( |
| std::enable_if_t<google::protobuf::is_proto_enum<T>::value, bool>) { |
| return true; |
| } |
| |
| template <typename T, typename = void> |
| constexpr bool IsProtocolBufferEnumImpl(...) { |
| return false; |
| } |
| |
| template <typename T> |
| inline constexpr bool is_protocol_buffer_enum_v = |
| IsProtocolBufferEnumImpl<T>(true); |
| |
| template <typename T> |
| inline constexpr bool is_dynamic_container_v = |
| Requires<T>([](auto v) -> decltype(v.insert(v.end(), *v.begin())) {}); |
| |
| template <typename T> |
| inline constexpr bool is_associative_container_v = is_dynamic_container_v<T>&& |
| Requires<T>([](auto v) -> decltype(v.find( |
| std::declval<typename decltype(v)::key_type>())) {}); |
| |
| template <typename T> |
| inline constexpr bool is_ostreamable_v = |
| Requires<T>([](auto&& v) -> decltype(std::declval<std::ostream&>() |
| << std::forward<decltype(v)>(v)) {}); |
| |
| template <typename T, typename = void> |
| struct is_memory_dictionary_compatible : std::false_type {}; |
| |
| template <typename T> |
| struct is_memory_dictionary_compatible< |
| T, std::enable_if_t<T::is_memory_dictionary_compatible_v>> |
| : std::true_type {}; |
| |
| // `BindAggregate` uses structured bindings to create a tuple of references to |
| // the fields on the input object. |
| // It has to be provided with the number of fields contained in the structure. |
| // We special case `0` because we can't do structured bindings there, and it is |
| // unnecessary anyway. |
| template <typename T> |
| auto BindAggregate(T&, std::integral_constant<int, 0>) { |
| return std::tie(); |
| } |
| // Implement the overloads from 1 to 64. |
| // There is no "variadic" way of doing this. |
| #define FUZZTEST_INTERNAL_BIND_AGGREGATE_(n, ...) \ |
| template <typename T> \ |
| auto BindAggregate(T& value, std::integral_constant<int, n>) { \ |
| auto& [__VA_ARGS__] = value; \ |
| return std::tie(__VA_ARGS__); \ |
| } |
| |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(1, x1); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(2, x1, x2); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(3, x1, x2, x3); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(4, x1, x2, x3, x4); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(5, x1, x2, x3, x4, x5); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(6, x1, x2, x3, x4, x5, x6); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(7, x1, x2, x3, x4, x5, x6, x7); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(8, x1, x2, x3, x4, x5, x6, x7, x8); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(9, x1, x2, x3, x4, x5, x6, x7, x8, x9); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(10, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(11, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(12, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(13, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(14, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(15, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(16, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(17, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(18, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(19, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(20, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(21, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(22, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(23, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(24, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(25, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(26, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(27, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(28, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(29, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(30, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(31, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(32, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(33, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(34, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(35, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(36, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(37, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(38, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(39, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(40, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(41, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(42, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(43, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(44, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(45, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(46, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(47, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(48, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(49, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(50, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(51, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(52, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51, x52); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(53, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51, x52, x53); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(54, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51, x52, x53, x54); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(55, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51, x52, x53, x54, x55); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(56, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51, x52, x53, x54, x55, |
| x56); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(57, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51, x52, x53, x54, x55, |
| x56, x57); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(58, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51, x52, x53, x54, x55, |
| x56, x57, x58); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(59, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51, x52, x53, x54, x55, |
| x56, x57, x58, x59); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(60, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51, x52, x53, x54, x55, |
| x56, x57, x58, x59, x60); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(61, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51, x52, x53, x54, x55, |
| x56, x57, x58, x59, x60, x61); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(62, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51, x52, x53, x54, x55, |
| x56, x57, x58, x59, x60, x61, x62); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(63, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51, x52, x53, x54, x55, |
| x56, x57, x58, x59, x60, x61, x62, x63); |
| FUZZTEST_INTERNAL_BIND_AGGREGATE_(64, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, |
| x29, x30, x31, x32, x33, x34, x35, x36, x37, |
| x38, x39, x40, x41, x42, x43, x44, x45, x46, |
| x47, x48, x49, x50, x51, x52, x53, x54, x55, |
| x56, x57, x58, x59, x60, x61, x62, x63, x64); |
| #undef FUZZTEST_INTERNAL_BIND_AGGREGATE_ |
| |
| // For N > 64, use std::get<I>. |
| // Some aggregate types like std::tuple provide this protocol, but so can user |
| // defined types. |
| template <typename T, int N> |
| auto BindAggregate(T& value, std::integral_constant<int, N>) { |
| static_assert(N > 64); |
| if constexpr (std::is_aggregate_v<T> && |
| !Requires<T>([](auto v) -> decltype(std::get<0>(v)) {})) { |
| static_assert(always_false<T>, |
| "Aggregate types are only supported up to 64 fields."); |
| } |
| // For the rest use the tuple API |
| return ApplyIndex<N>( |
| [&](auto... I) { return std::tie(std::get<I>(value)...); }); |
| } |
| |
| // We disable `T` because `{T&&}` would work for non aggregates as a move |
| // construction. |
| template <typename T> |
| struct AnythingBut { |
| template <typename U, std::enable_if_t<!std::is_same_v<U, T>, int> = 0> |
| operator U&&() const { |
| std::abort(); |
| } |
| }; |
| |
| // Try to call ApplyIndex from I all the way down to 0. |
| template <size_t I, typename F> |
| constexpr std::optional<int> ApplyIndexFor(F f) { |
| if constexpr (ApplyIndex<I>(f)) { |
| return I; |
| } |
| if constexpr (I == 0) { |
| return std::nullopt; |
| } else { |
| return ApplyIndexFor<I - 1>(f); |
| } |
| } |
| |
| // Try applying aggregate initialization to `T` with different number of |
| // arguments. We start at 64 and go down until one works. |
| template <typename T> |
| constexpr std::optional<int> DetectBraceInitCount() { |
| constexpr auto can_init_impl = |
| [](auto... I) -> decltype(T{(I, AnythingBut<T>{})...}) {}; |
| constexpr auto can_init = [](auto... I) { |
| return std::is_invocable_v<decltype(can_init_impl), decltype(I)...>; |
| }; |
| if constexpr (!std::is_aggregate_v<T>) { |
| return std::nullopt; |
| } |
| |
| return ApplyIndexFor<64>(can_init); |
| } |
| |
| // This allows us to determine whether T has a base class. If it does, it is |
| // initialized with a one more field than we can bind to it. |
| template <typename T> |
| struct AnythingButBaseOf { |
| template <typename U, std::enable_if_t<!std::is_base_of_v<U, T>, int> = 0> |
| operator U&&() const { |
| std::abort(); |
| } |
| }; |
| |
| // Detect the number of fields bindable with `auto& [...] = t;`. |
| // This can be less than the number of fields used to initialize `T` if `T` |
| // inherits from an empty base class. Multiple inheritance is not supported. |
| template <typename T> |
| constexpr std::optional<int> DetectBindableFieldCount() { |
| // Classes which inherit from a base are initialized with an extra first field |
| // corresponding to the base class. We know from DetectBraceInitCount() that |
| // `T` is initializable with N fields which are not a `T`. If `T` is not |
| // initializable when we insist that the first field is not a base of `T`, |
| // then we know that T has a base class and needs to be adjusted accordingly. |
| // We don't worry about whether the potential base classes of T are empty: if |
| // they are not, then binding will fail later anyways with a good error |
| // message, and there is no way around this. |
| constexpr std::optional<int> brace_init_count_opt = DetectBraceInitCount<T>(); |
| constexpr int brace_init_count = brace_init_count_opt.value_or(0); |
| |
| // Detect if the first initialization field is a base class. |
| constexpr auto no_base_impl = [](auto... I) |
| -> decltype(T{AnythingButBaseOf<T>{}, (I, AnythingBut<T>{})...}) {}; |
| constexpr auto no_base = [](auto... I) { |
| return std::is_invocable_v<decltype(no_base_impl), decltype(I)...>; |
| }; |
| |
| if constexpr (brace_init_count < 1) { |
| return brace_init_count_opt; |
| } else if constexpr (ApplyIndex<brace_init_count - 1>(no_base)) { |
| return brace_init_count; |
| } |
| |
| // Detect if the second initialization field is a base class. |
| constexpr auto no_two_bases_impl = |
| [](auto... I) -> decltype(T{AnythingBut<T>{}, AnythingButBaseOf<T>{}, |
| (I, AnythingBut<T>{})...}) {}; |
| constexpr auto no_two_bases = [](auto... I) { |
| return std::is_invocable_v<decltype(no_two_bases_impl), decltype(I)...>; |
| }; |
| |
| // Check for multiple inheritence. This condition also triggers if we have a |
| // struct whose first field is its base class. The latter case should be |
| // somewhat rare, because: |
| // - We don't currently support structs with a non-empty parent class |
| // (these cannot be decomposed in `BindAggregate()`). |
| // - It is rare to have a struct with a member that is an empty class, as |
| // would be the case if the parent were empty. |
| if constexpr (brace_init_count >= 2) { |
| static_assert(ApplyIndex<brace_init_count - 2>(no_two_bases), |
| "Multiple inheritance is not currently supported, nor are " |
| "structs whose first fields are their base class."); |
| } |
| // We have exactly one base class. |
| return brace_init_count - 1; |
| } |
| |
| template <typename T> |
| constexpr std::optional<int> DetectAggregateSize() { |
| if constexpr (is_pair_v<T> || is_tuple_v<T> || is_array_v<T>) { |
| return std::tuple_size_v<T>; |
| } else { |
| return DetectBindableFieldCount<T>(); |
| } |
| } |
| |
| // Detect the number and types of the fields. |
| template <typename T, int N = *DetectAggregateSize<std::remove_cv_t<T>>()> |
| auto DetectBindAggregate(T& v) { |
| return BindAggregate(v, std::integral_constant<int, N>{}); |
| } |
| |
| template <typename T> |
| inline constexpr bool is_bindable_aggregate_v = |
| Requires<T&>([](auto& v) -> decltype(DetectBindAggregate(v)) {}); |
| |
| template <int I, typename T> |
| struct ExtractTemplateParameterImpl; |
| |
| template <int I, template <typename...> class C, typename... T> |
| struct ExtractTemplateParameterImpl<I, C<T...>> { |
| using type = std::tuple_element_t<I, std::tuple<T...>>; |
| }; |
| |
| // Evaluates to the Ith template parameter of the class template |
| // instantiation `T`. Eg: |
| // `ExtractTemplateParameter<1, Foo<int, double, char>>` |
| // evaluates to `double`. |
| template <int I, typename T> |
| using ExtractTemplateParameter = |
| typename ExtractTemplateParameterImpl<I, T>::type; |
| |
| template <typename T> |
| struct DropConstImpl { |
| using type = std::remove_const_t<T>; |
| }; |
| |
| template <template <typename...> class C, typename... T> |
| struct DropConstImpl<C<T...>> { |
| using type = C<typename DropConstImpl<T>::type...>; |
| }; |
| |
| // Drop `const` recursively from class templates. |
| // Eg: |
| // `DropConst<std::vector<std::pair<const K, std::tuple<const int>>>` |
| // evaluates to |
| // `std::vector<std::pair<K, std::tuple<int>>>` |
| template <typename T> |
| using DropConst = typename DropConstImpl<T>::type; |
| |
| // MakeDependentType<T, U...> evaluates to `T` but makes the declaration type |
| // dependent on templates `U...`. |
| // This allows delaying name lookup for the second phase when the types involved |
| // are fully defined. |
| // See https://en.cppreference.com/w/cpp/language/two-phase_lookup |
| template <typename T, typename... Dependent> |
| using MakeDependentType = std::enable_if_t<(always_true<Dependent> && ...), T>; |
| |
| } // namespace fuzztest::internal |
| |
| #endif // FUZZTEST_FUZZTEST_INTERNAL_META_H_ |