Skip to content
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
6 changes: 3 additions & 3 deletions etc/clang-flags.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
include_guard(GLOBAL)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD 20)
Copy link
Member

@JeffGarland JeffGarland Jul 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean this works around the compile bug for tests, but my bug report would still be a problem?

sorry had to refresh my memory -- this directly tests my issue, thanks


set(CMAKE_CXX_FLAGS
"-stdlib=libc++ -Wall -Wextra "
Expand Down Expand Up @@ -28,13 +28,13 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
FORCE
)
set(CMAKE_CXX_FLAGS_TSAN
"-O3 -g -DNDEBUG -fsanitize=thread"
"-O3 -g -fsanitize=thread"
CACHE STRING
"C++ TSAN Flags"
FORCE
)
set(CMAKE_CXX_FLAGS_ASAN
"-O3 -g -DNDEBUG -fsanitize=address,undefined,leak"
"-O3 -g -fsanitize=address,undefined,leak"
CACHE STRING
"C++ ASAN Flags"
FORCE
Expand Down
6 changes: 3 additions & 3 deletions etc/gcc-flags.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
include_guard(GLOBAL)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD 20)

set(CMAKE_CXX_FLAGS "-Wall -Wextra " CACHE STRING "CXX_FLAGS" FORCE)

Expand All @@ -23,13 +23,13 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
FORCE
)
set(CMAKE_CXX_FLAGS_TSAN
"-O3 -g -DNDEBUG -fsanitize=thread"
"-O3 -g -fsanitize=thread"
CACHE STRING
"C++ TSAN Flags"
FORCE
)
set(CMAKE_CXX_FLAGS_ASAN
"-O3 -g -DNDEBUG -fsanitize=address,undefined,leak"
"-O3 -g -fsanitize=address,undefined,leak"
CACHE STRING
"C++ ASAN Flags"
FORCE
Expand Down
8 changes: 1 addition & 7 deletions etc/gcc-toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@ include_guard(GLOBAL)
set(CMAKE_C_COMPILER gcc)
set(CMAKE_CXX_COMPILER g++)

set(CMAKE_CXX_FLAGS
"-std=c++20 \
-Wall -Wextra "
CACHE STRING
"CXX_FLAGS"
FORCE
)
set(CMAKE_CXX_FLAGS "-Wall -Wextra " CACHE STRING "CXX_FLAGS" FORCE)

set(CMAKE_CXX_FLAGS_DEBUG
"-O0 -fno-inline -g3"
Expand Down
155 changes: 85 additions & 70 deletions tests/beman/optional/optional_range_support.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,19 @@

#include <beman/optional/detail/iterator.hpp>
#include <beman/optional/test_types.hpp>
#include <beman/optional/test_utilities.hpp>

#include <algorithm>
#include <concepts>
#include <cstdlib>
#if defined(__cpp_lib_format_ranges)
#include <format>
#endif
#include <functional>
#include <ranges>
#include <tuple>
#include <optional>
#include <type_traits>
#include <unordered_set>
#include <vector>

#define CONSTEXPR_EXPECT_EQ(val1, val2) \
if (::std::is_constant_evaluated()) { \
if (!((val1) == (val2))) { \
::std::abort(); \
} \
} else \
EXPECT_EQ(val1, val2)

#define CONSTEXPR_EXPECT_TRUE(val) \
if (::std::is_constant_evaluated()) { \
if (!(val)) { \
Expand All @@ -45,21 +35,20 @@
} else \
EXPECT_TRUE(val)

#define CONSTEXPR_ASSERT_TRUE(val) \
if (::std::is_constant_evaluated()) { \
if (!(val)) { \
::std::abort(); \
} \
} else \
ASSERT_TRUE(val)
template <typename U, typename V>
auto gtest_expect_eq(U&& val1, V&& val2) {
EXPECT_EQ(std::forward<U>(val1), std::forward<V>(val2));
}

#define CONSTEXPR_ASSERT_FALSE(val) \
if (::std::is_constant_evaluated()) { \
if (val) { \
::std::abort(); \
} \
} else \
ASSERT_FALSE(val)
template <typename U, typename V>
constexpr auto constexpr_expect_eq(U&& val1, V&& val2) {
if (::std::is_constant_evaluated()) {
if (!(val1 == val2))
std::abort();
} else {
gtest_expect_eq(std::forward<U>(val1), std::forward<V>(val2));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nice improvement

}

using namespace beman::optional::tests;

Expand Down Expand Up @@ -132,10 +121,10 @@ TEST(RangeSupportTest, BeginOnEmptyOptional) {
// e.g. const_iterator = optional<T>::const_iterator if opt is optional<T>
using const_iterator = typename std::remove_reference_t<decltype(opt)>::const_iterator;

CONSTEXPR_EXPECT_EQ(opt.begin(), iterator());
constexpr_expect_eq(iterator(), opt.begin());

const auto& const_opt = opt;
CONSTEXPR_EXPECT_EQ(const_opt.begin(), const_iterator());
constexpr_expect_eq(const_iterator(), const_opt.begin());
};

test(beman::optional::optional<int>{});
Expand All @@ -144,9 +133,11 @@ TEST(RangeSupportTest, BeginOnEmptyOptional) {
test(beman::optional::optional<no_default_ctor>{});
test(beman::optional::optional<base>{});
test(beman::optional::optional<derived>{});
return true;
};
static_assert((lambda(), true));
lambda();
using beman::optional::tests::constify;
EXPECT_TRUE(constify(lambda()));
EXPECT_TRUE(lambda());
}

TEST(RangeSupportTest, BeginOnNonEmptyOptional) {
Expand All @@ -158,10 +149,10 @@ TEST(RangeSupportTest, BeginOnNonEmptyOptional) {
// e.g. const_iterator = optional<T>::const_iterator if opt is optional<T>
using const_iterator = typename std::remove_reference_t<decltype(opt)>::const_iterator;

CONSTEXPR_EXPECT_EQ(opt.begin(), iterator(&*opt));
constexpr_expect_eq(opt.begin(), iterator(&*opt));

const auto& const_opt = opt;
CONSTEXPR_EXPECT_EQ(const_opt.begin(), const_iterator(&*opt));
constexpr_expect_eq(const_opt.begin(), const_iterator(&*opt));
};

test(beman::optional::optional<int>{26});
Expand All @@ -172,9 +163,10 @@ TEST(RangeSupportTest, BeginOnNonEmptyOptional) {
test(beman::optional::optional<no_default_ctor>{no_default_ctor{empty{}}});
test(beman::optional::optional<base>{base{}});
test(beman::optional::optional<derived>{derived{}});
return true;
};
static_assert((lambda(), true));
lambda();
EXPECT_TRUE(constify(lambda()));
EXPECT_TRUE(lambda());
}

TEST(RangeSupportTest, EndOnEmptyOptional) {
Expand All @@ -186,10 +178,10 @@ TEST(RangeSupportTest, EndOnEmptyOptional) {
// e.g. const_iterator = optional<T>::const_iterator if opt is optional<T>
using const_iterator = typename std::remove_reference_t<decltype(opt)>::const_iterator;

CONSTEXPR_EXPECT_EQ(opt.end(), iterator());
constexpr_expect_eq(opt.end(), iterator());

const auto& const_opt = opt;
CONSTEXPR_EXPECT_EQ(const_opt.end(), const_iterator());
constexpr_expect_eq(const_opt.end(), const_iterator());
};

test(beman::optional::optional<int>{});
Expand All @@ -198,9 +190,10 @@ TEST(RangeSupportTest, EndOnEmptyOptional) {
test(beman::optional::optional<no_default_ctor>{});
test(beman::optional::optional<base>{});
test(beman::optional::optional<derived>{});
return true;
};
static_assert((lambda(), true));
lambda();
EXPECT_TRUE(constify(lambda()));
EXPECT_TRUE(lambda());
}

TEST(RangeSupportTest, EndOnNonEmptyOptional) {
Expand All @@ -212,10 +205,10 @@ TEST(RangeSupportTest, EndOnNonEmptyOptional) {
// e.g. const_iterator = optional<T>::const_iterator if opt is optional<T>
using const_iterator = typename std::remove_reference_t<decltype(opt)>::const_iterator;

CONSTEXPR_EXPECT_EQ(opt.end(), iterator(&*opt + 1));
constexpr_expect_eq(opt.end(), iterator(&*opt + 1));

const auto& const_opt = opt;
CONSTEXPR_EXPECT_EQ(const_opt.end(), const_iterator(&*opt + 1));
constexpr_expect_eq(const_opt.end(), const_iterator(&*opt + 1));
};

test(beman::optional::optional<int>{26});
Expand All @@ -226,12 +219,14 @@ TEST(RangeSupportTest, EndOnNonEmptyOptional) {
test(beman::optional::optional<no_default_ctor>{no_default_ctor{empty{}}});
test(beman::optional::optional<base>{base{}});
test(beman::optional::optional<derived>{derived{}});
return true;
};
static_assert((lambda(), true));
lambda();
EXPECT_TRUE(constify(lambda()));
EXPECT_TRUE(lambda());
}

#if ((__GNUC__ >= 15) && (__GNUC_MINOR__ >= 1) && (__GNUC_PATCHLEVEL__ >= 1)) || ((__GNUC__ >= 16))
#if (__cplusplus >= 202302L) && \
(((__GNUC__ >= 15) && (__GNUC_MINOR__ >= 1) && (__GNUC_PATCHLEVEL__ >= 1)) || ((__GNUC__ >= 16)))
static_assert(std::format_kind<beman::optional::optional<int>> == std::range_format::disabled);
#endif

Expand All @@ -258,70 +253,89 @@ TEST(RangeSupportTest, FormatOptionalIsStillDisabled) {
#endif
}

template <typename U>
auto gtest_assert_true(U&& val1) {
ASSERT_TRUE(std::forward<U>(val1));
}

template <typename U>
constexpr auto constexpr_assert(U&& val1) {
if (::std::is_constant_evaluated()) {
if (!(val1))
std::abort();
} else {
gtest_assert_true(std::forward<U>(val1));
}
}

TEST(RangeSupportTest, LoopOverEmptyRange) {
auto lambda = [&] {
auto lambda = [&]() -> bool {
beman::optional::optional<int> empty;
CONSTEXPR_ASSERT_FALSE(empty.has_value());
constexpr_assert(!empty.has_value());

for ([[maybe_unused]] auto _ : empty) {
CONSTEXPR_ASSERT_TRUE(false) << "Should not be reached: expected not to loop over empty optional";
constexpr_assert(false); // << "Should not be reached: expected not to loop over empty optional";
}
return true;
};
static_assert((lambda(), true));
lambda();
EXPECT_TRUE(constify(lambda()));
EXPECT_TRUE(lambda());
}

TEST(RangeSupportTest, LoopOverNonEmptyRange) {
auto lambda = [&] {
const int expected_value = 0xCAFEBABE;
beman::optional::optional<int> empty{expected_value};
CONSTEXPR_ASSERT_TRUE(empty.has_value());
constexpr_assert(empty.has_value());

bool entered_loop = false;
for (auto i : empty) {
CONSTEXPR_EXPECT_EQ(i, expected_value);
constexpr_expect_eq(i, expected_value);
entered_loop = true;
}
CONSTEXPR_EXPECT_TRUE(entered_loop);
constexpr_expect_eq(entered_loop, true);
return true;
};
static_assert((lambda(), true));
lambda();
EXPECT_TRUE(constify(lambda()));
EXPECT_TRUE(lambda());
}

TEST(RangeSupportTest, LoopOptionalAccess) {
auto lambda = [&] {
// Example from P3168R2: should access the value from an optional object.
const int expected_value = 0xCAFEBABE;
const auto get_optional = [&]() -> beman::optional::optional<int> { return expected_value; };
CONSTEXPR_ASSERT_TRUE(get_optional().has_value());
constexpr_assert(get_optional().has_value());

for (auto&& opt : get_optional()) {
CONSTEXPR_EXPECT_EQ(opt, expected_value); // usage of opt here is safe
constexpr_expect_eq(opt, expected_value); // usage of opt here is safe
}
return true;
};
static_assert((lambda(), true));
lambda();
EXPECT_TRUE(constify(lambda()));
EXPECT_TRUE(lambda());
}

TEST(RangeSupportTest, LoopOptionalAssignment) {
auto lambda = [&] {
constexpr auto lambda = [] {
// Example from P3168R2: should mutate the value from an optional object.
const int initial_expected_value = 0xCAFEBABE;
const int expected_value = 0xDEADBEEF;
const auto get_optional = [&]() -> beman::optional::optional<int> { return initial_expected_value; };
CONSTEXPR_ASSERT_TRUE(get_optional().has_value());
CONSTEXPR_ASSERT_TRUE(get_optional().value() == initial_expected_value);
constexpr int initial_expected_value = 0xCAFEBABE;
constexpr int expected_value = 0xDEADBEEF;
constexpr auto get_optional = [=]() -> beman::optional::optional<int> { return initial_expected_value; };
constexpr_assert(get_optional().has_value());
constexpr_assert(get_optional().value() == initial_expected_value);

auto opt_int = get_optional();
for (auto&& opt : opt_int) {
CONSTEXPR_EXPECT_EQ(opt, initial_expected_value);
constexpr_expect_eq(opt, initial_expected_value);
opt = expected_value; // usage of opt here is safe
}
CONSTEXPR_ASSERT_TRUE(opt_int.has_value());
CONSTEXPR_EXPECT_EQ(opt_int.value(), expected_value);
constexpr_assert(opt_int.has_value());
constexpr_expect_eq(opt_int.value(), expected_value);
return true;
};
static_assert((lambda(), true));
lambda();
EXPECT_TRUE(constify(lambda()));
EXPECT_TRUE(lambda());
}

TEST(RangeSupportTest, RangeChainExample) {
Expand Down Expand Up @@ -407,13 +421,14 @@ TEST(RangeSupportTest, PythagoreanTriples) {
};
constexpr const std::tuple k100th_triple = {
26, 168, 170}; // The 100th Pythagorean triple with x, y, z <= 200.
ASSERT_EQ(bruteforce_generate_nth(100, 200), k100th_triple);
EXPECT_EQ(bruteforce_generate_nth(100, 200), k100th_triple);

// Generate the 100th Pythagorean triple with ranges.
auto&& r = triples | std::views::drop(99) | std::views::take(1);
EXPECT_TRUE(std::ranges::equal(r, std::vector{k100th_triple}));
}
return true;
};
static_assert((lambda(), true));
lambda();
EXPECT_TRUE(constify(lambda()));
EXPECT_TRUE(lambda());
}