blob: 9a918e1042e573be0161760e8e8857cd62b555e6 [file] [log] [blame]
// 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_