Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional Extend checks. #32

Merged
merged 12 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .clangd
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@ Diagnostics:

---
If:
PathMatch: .*_test.cc
PathMatch: .*_test.cc

Diagnostics:
ClangTidy:
Remove: [cppcoreguidelines-avoid-non-const-global-variables, cppcoreguidelines-owning-memory]

---
If:
PathMatch: .*[.]mope

Diagnostics:
Suppress: '*'
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 0.2.25

* Added concept `mbo::types::IsVariant`.
* Added concept `mbo::types::HasVariantMember`.

# 0.2.24

* Improved `Extend` support.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ The C++ library is organized in functional groups each residing in their own dir
* concept `IsBracesConstructibleV` determines whether a type can be constructe from given argument types.
* concept `IsPair` determines whether a type is a `std::pair`.
* concept `IsSameAsAnyOfRaw` / `NotSameAsAnyOfRaw` which determine whether type is one of a list of types.
* concept `IsVariant` determines whether a type is a `std::variant` type.
* mbo/types:tstring_cc, mbo/types/tstring.h
* struct `tstring`: Implements type `tstring` a compile time string-literal type.
* operator `operator"" _ts`: String literal support for Clang, GCC and derived compilers.
Expand Down
2 changes: 1 addition & 1 deletion WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ llvm_toolchain(
},
sha256 = {
"linux-aarch64": "6dd62762285326f223f40b8e4f2864b5c372de3f7de0731cb7cd55ca5287b75a",
"limux-x86_64": "884ee67d647d77e58740c1e645649e29ae9e8a6fe87c1376be0f3a30f3cc9ab3",
"linux-x86_64": "884ee67d647d77e58740c1e645649e29ae9e8a6fe87c1376be0f3a30f3cc9ab3",
"darwin-aarch64": "1264eb3c2a4a6d5e9354c3e5dc5cb6c6481e678f6456f36d2e0e566e9400fcad",
"darwin-x86_64": "d16b6d536364c5bec6583d12dd7e6cf841b9f508c4430d9ee886726bd9983f1c",
},
Expand Down
4 changes: 2 additions & 2 deletions mbo/types/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ cc_test(
cc_library(
name = "tuple_cc",
hdrs = ["tuple.h"],
visibility = ["//visibility:private"],
deps = ["traits_cc"],
visibility = ["//mbo/types/internal:__pkg__"],
deps = [":traits_cc"],
)

cc_test(
Expand Down
44 changes: 42 additions & 2 deletions mbo/types/extend_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,20 @@
#include "mbo/types/internal/decompose_count.h"
#include "mbo/types/internal/extend.h" // IWYU pragma: keep
#include "mbo/types/traits.h" // IWYU pragma: keep
#include "mbo/types/tuple.h"

namespace std {

template<typename Sink>
void AbslStringify(Sink& sink, const std::pair<const int, std::string>& val) { // NOLINT(cert-dcl58-cpp)
absl::Format(&sink, R"({%d, "%s"})", val.first, val.second);
}

template<typename Sink, typename... Args>
void AbslStringify(Sink& sink, const std::variant<Args...>& val) { // NOLINT(cert-dcl58-cpp)
std::visit([&sink](auto&& arg) { absl::Format(&sink, "%v", arg); }, val);
}

} // namespace std

namespace mbo::types {
Expand Down Expand Up @@ -341,6 +349,7 @@ struct WithUnion : mbo::types::Extend<WithUnion> {

static_assert(!HasUnionMember<int>);

// NOLINTBEGIN(*-magic-numbers)
static_assert(types_internal::AggregateInitializeTest<WithUnion>::IsInitializable<0>::value);
static_assert(types_internal::AggregateInitializeTest<WithUnion>::IsInitializable<1>::value);
static_assert(types_internal::AggregateInitializeTest<WithUnion>::IsInitializable<2>::value);
Expand All @@ -354,6 +363,7 @@ static_assert(types_internal::DecomposeInfo<WithUnion>::kFieldCount == 4);
static_assert(types_internal::DecomposeInfo<WithUnion>::kCountBases == 0);
static_assert(types_internal::DecomposeInfo<WithUnion>::kCountEmptyBases == 1);
static_assert(types_internal::DecomposeCountImpl<WithUnion>::value == 3);
// NOLINTEND(*-magic-numbers)

static_assert(HasUnionMember<WithUnion>);

Expand Down Expand Up @@ -593,6 +603,7 @@ struct UseCrtp1 : Extend<UseCrtp1> {
Crtp1 crtp;
};

// NOLINTBEGIN(*-magic-numbers)
static_assert(!types_internal::AggregateInitializeTest<UseCrtp1>::IsInitializable<0>::value);
static_assert(!types_internal::AggregateInitializeTest<UseCrtp1>::IsInitializable<1>::value);
static_assert(types_internal::AggregateInitializeTest<UseCrtp1>::IsInitializable<2>::value);
Expand All @@ -601,6 +612,7 @@ static_assert(!types_internal::AggregateInitializeTest<UseCrtp1>::IsInitializabl
static_assert(!types_internal::AggregateInitializeTest<UseCrtp1>::IsInitializable<5>::value);
static_assert(!types_internal::AggregateInitializeTest<UseCrtp1>::IsInitializable<6>::value);
static_assert(!types_internal::AggregateInitializeTest<UseCrtp1>::IsInitializable<7>::value);
// NOLINTEND(*-magic-numbers)

static_assert(types_internal::AggregateInitializerCount<UseCrtp1>::value == 2);
static_assert(types_internal::DecomposeInfo<UseCrtp1>::kInitializerCount == 2);
Expand All @@ -627,6 +639,7 @@ struct UseBoth : Extend<UseBoth> {

static_assert(IsAggregate<UseBoth>);

// NOLINTBEGIN(*-magic-numbers)
static_assert(!types_internal::AggregateInitializeTest<UseBoth>::IsInitializable<0>::value);
static_assert(!types_internal::AggregateInitializeTest<UseBoth>::IsInitializable<1>::value);
static_assert(!types_internal::AggregateInitializeTest<UseBoth>::IsInitializable<2>::value);
Expand All @@ -635,6 +648,7 @@ static_assert(!types_internal::AggregateInitializeTest<UseBoth>::IsInitializable
static_assert(!types_internal::AggregateInitializeTest<UseBoth>::IsInitializable<5>::value);
static_assert(!types_internal::AggregateInitializeTest<UseBoth>::IsInitializable<6>::value);
static_assert(!types_internal::AggregateInitializeTest<UseBoth>::IsInitializable<7>::value);
// NOLINTEND(*-magic-numbers)

static_assert(types_internal::IsAggregateInitializableWithNumArgs<UseBoth, 3>);
static_assert(types_internal::AggregateInitializeTest<UseBoth>::IsInitializable<3>::value);
Expand Down Expand Up @@ -662,10 +676,22 @@ TEST_F(ExtendTest, NoDefaultConstructor) {
}

struct AbslFlatHashMapUser : Extend<AbslFlatHashMapUser> {
using MboTypesExtendDoNotPrintFieldNames = void;
absl::flat_hash_map<int, std::string> flat_hash_map;
};

static_assert(std::is_default_constructible_v<AbslFlatHashMapUser>);
static_assert(!std::is_trivially_default_constructible_v<AbslFlatHashMapUser>);
static_assert(std::default_initializable<AbslFlatHashMapUser>);

static_assert(std::is_destructible_v<AbslFlatHashMapUser>);
static_assert(!std::is_trivially_destructible_v<AbslFlatHashMapUser>);

static_assert(!types::HasUnionMember<AbslFlatHashMapUser>);
static_assert(!types::HasVariantMember<AbslFlatHashMapUser>);

static_assert(DecomposeCountV<AbslFlatHashMapUser> == 1);
static_assert(!types_internal::SupportsFieldNames<AbslFlatHashMapUser>);

TEST_F(ExtendTest, AbseilFlatHashMapMember) {
const AbslFlatHashMapUser data = {
.flat_hash_map = {{25, "25"}, {42, "42"}},
Expand All @@ -674,7 +700,21 @@ TEST_F(ExtendTest, AbseilFlatHashMapMember) {
data.ToString(), AnyOf(EndsWith(R"({{25, "25"}, {42, "42"}}})"), EndsWith(R"({{42, "42"}, {25, "25"}}})")));
}

static_assert(DecomposeCountV<AbslFlatHashMapUser> == 1);
struct WithVariant : Extend<WithVariant> {
std::variant<int, unsigned> value;
};

static_assert(types::HasVariantMember<WithVariant>);

static_assert(DecomposeCountV<WithVariant> == 1);
static_assert(types_internal::SupportsFieldNames<WithVariant> == kStructNameSupport);

TEST_F(ExtendTest, VariantMember) {
const WithVariant data = {
.value = 69,
};
EXPECT_THAT(data.ToString(), Conditional(kStructNameSupport, R"({.value: 69})", R"({69})"));
}

} // namespace
} // namespace mbo::types
22 changes: 21 additions & 1 deletion mbo/types/internal/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,29 @@ cc_library(
hdrs = ["struct_names.h"],
deps = [
":traits_cc",
"//mbo/types:tuple_cc",
"@com_google_absl//absl/types:span",
],
)

cc_test(
name = "struct_names_test",
srcs = ["struct_names_test.cc"],
deps = [
":struct_names_cc",
"//mbo/types:tstring_cc",
"@com_google_googletest//:gtest_main",
],
)

cc_library(
name = "traits_cc",
hdrs = [
"binary_search.h",
"decompose_count.h",
"is_braces_constructible.h",
],
deps = ["cases_cc"],
deps = [":cases_cc"],
)

cc_library(
Expand All @@ -66,3 +77,12 @@ mope_test(
outs = ["decompose_count.h"],
clang_format = True,
)

cc_test(
name = "binary_search_test",
srcs = ["binary_search_test.cc"],
deps = [
":traits_cc",
"@com_google_googletest//:gtest_main",
]
)
101 changes: 55 additions & 46 deletions mbo/types/internal/binary_search.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,71 +23,80 @@

namespace mbo::types::types_internal {

// Template `BinarySearch` - finds a value in [Start, End[ for which Predicate is true.
// Template `BinarySearch` - find higest value in `[Start, End[` for which `Predicate` is true.
// Returns `NotFound` otherwise.
// The `Predicate` must provide a boolean constant `value`.

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, std::size_t NotFound>
struct BinarySearch;

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
using BinarySearchImpl = std::conditional_t<
(End - Start <= 1),
std::integral_constant<std::size_t, Start>,
std::conditional_t<
Predicate<(Start + End) / 2>::value,
BinarySearch<Predicate, (Start + End) / 2, End>,
BinarySearch<Predicate, Start, (Start + End) / 2>>>;
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, std::size_t NotFound>
using BinarySearchImpl = std::conditional_t < (Start + 1 >= End),
std::conditional_t<
Start<
End && Predicate<Start>::value,
std::integral_constant<std::size_t, Start>,
std::integral_constant<std::size_t, NotFound>>,
std::conditional_t<
Predicate<(Start + End) / 2>::value,
BinarySearch<Predicate, (Start + End) / 2, End, NotFound>,
BinarySearch<Predicate, Start, (Start + End) / 2, NotFound>>>;

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
struct BinarySearch : BinarySearchImpl<Predicate, Start, End> {};
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, size_t NotFound = End>
struct BinarySearch : BinarySearchImpl<Predicate, Start, End, NotFound> {};

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
constexpr std::size_t BinarySearchV = BinarySearch<Predicate, Start, End>::value;
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, std::size_t NotFound = End>
constexpr std::size_t BinarySearchV = BinarySearch<Predicate, Start, End, NotFound>::value;

// Template `LinearSearch`
//
// Finds the first value in [Start, End[ for which Predicate is true.
// Finds the first value in `[Start, End[` for which `Predicate` is true.
// Returns `NotFound` otherwise.
// The `Predicate` must provide a boolean constant `value`.

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, size_t NotFound>
struct LinearSearch;

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, size_t NotFound>
using LinearSearchImpl = std::conditional_t<
(Start + 1 >= End),
std::integral_constant<std::size_t, Start>,
Start >= End,
std::integral_constant<std::size_t, NotFound>,
std::conditional_t<
Predicate<Start>::value,
std::integral_constant<std::size_t, Start>,
LinearSearch<Predicate, Start + 1, End>>>;
LinearSearch<Predicate, Start + 1, End, NotFound>>>;

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
struct LinearSearch : LinearSearchImpl<Predicate, Start, End> {};
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, size_t NotFound = End>
struct LinearSearch : LinearSearchImpl<Predicate, Start, End, NotFound> {};

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
constexpr std::size_t LinearSearchV = LinearSearch<Predicate, Start, End>::value;
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, size_t NotFound = End>
constexpr std::size_t LinearSearchV = LinearSearch<Predicate, Start, End, NotFound>::value;

// Template `MaxSearch`
//
// Finds the highest value in [Start, End[ for which Predicate is true.
// Requires that [Start] is true. Otherwise returns Start.
// In other words it find the last for which the Predicate returns true.
// Finds the highest value in `[Start, End[` for which `Predicate` is true.
// Requires that `[Start]` is true. Otherwise returns `NotFound`.
// In other words it find the last for which the `Predicate` returns true.
// This is brute force `BinarySearch` and in contrast to the former it requires `Predicate` to be true for **all** left
// values.

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, size_t NotFound>
struct MaxSearch;

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, size_t NotFound>
using MaxSearchImpl = std::conditional_t<
(Start + 1 >= End),
std::integral_constant<std::size_t, Start>,
(Start >= End),
std::integral_constant<std::size_t, NotFound>,
std::conditional_t<
Predicate<Start + 1>::value,
MaxSearch<Predicate, Start + 1, End>,
std::integral_constant<std::size_t, Start>>>;
Predicate<Start>::value,
MaxSearch<Predicate, Start + 1, End, Start>,
std::integral_constant<std::size_t, NotFound>>>;

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
struct MaxSearch : MaxSearchImpl<Predicate, Start, End> {};
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, size_t NotFound = End>
struct MaxSearch : MaxSearchImpl<Predicate, Start, End, NotFound> {};

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
constexpr std::size_t MaxSearchV = MaxSearch<Predicate, Start, End>::value;
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, size_t NotFound = End>
constexpr std::size_t MaxSearchV = MaxSearch<Predicate, Start, End, NotFound>::value;

// Template `ReverseSearch`
//
Expand All @@ -96,23 +105,23 @@ constexpr std::size_t MaxSearchV = MaxSearch<Predicate, Start, End>::value;
// Returns `End` if no value was found.
// The smallest value that can be returned is Start, independent of conditions.

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, size_t NotFound>
struct ReverseSearch;

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, size_t NotFound>
using ReverseSearchImpl = std::conditional_t<
(End <= Start),
std::integral_constant<std::size_t, Start>,
std::integral_constant<std::size_t, NotFound>,
std::conditional_t<
Predicate<End - 1>::value,
std::integral_constant<std::size_t, End - 1>,
ReverseSearch<Predicate, Start, End - 1>>>;
ReverseSearch<Predicate, Start, End - 1, NotFound>>>;

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
struct ReverseSearch : ReverseSearchImpl<Predicate, Start, End> {};
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, size_t NotFound = End>
struct ReverseSearch : ReverseSearchImpl<Predicate, Start, End, NotFound> {};

template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End>
constexpr std::size_t ReverseSearchV = ReverseSearch<Predicate, Start, End>::value;
template<template<std::size_t> typename Predicate, std::size_t Start, std::size_t End, size_t NotFound = End>
constexpr std::size_t ReverseSearchV = ReverseSearch<Predicate, Start, End, NotFound>::value;

} // namespace mbo::types::types_internal

Expand Down
Loading
Loading