Skip to content

Commit 25386bc

Browse files
Merge branch 'main' of https://github.com/beman-project/optional26 into static-msg
2 parents e388389 + 863a89c commit 25386bc

File tree

8 files changed

+387
-255
lines changed

8 files changed

+387
-255
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ jobs:
1616
- {name: "Ubuntu Clang 18", os: ubuntu-24.04, toolchain: "clang-18", clang_version: 18, installed_clang_version: 17, cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "}
1717
# Note: clang-19 + Asan setup causes errors on some platforms. Temporary skip some checks via .asan_options.
1818
- {name: "Ubuntu Clang 19", os: ubuntu-24.04, toolchain: "clang-19", clang_version: 19, installed_clang_version: 17, cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" ", asan_options: "new_delete_type_mismatch=0"}
19-
- {name: "Ubuntu GCC 11", os: ubuntu-24.04, toolchain: "gcc-11", cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "}
2019
- {name: "Ubuntu GCC 12", os: ubuntu-24.04, toolchain: "gcc-12", cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "}
2120
- {name: "Ubuntu GCC 13", os: ubuntu-24.04, toolchain: "gcc-13", cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "}
2221
- {name: "Ubuntu GCC 14", os: ubuntu-24.04, toolchain: "gcc-14", cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "}

etc/gcc-11-toolchain.cmake

Lines changed: 0 additions & 9 deletions
This file was deleted.

include/beman/optional26/detail/iterator.hpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,20 @@ struct contiguous_iterator : public base_contiguous_iterator<T, Container> {
4343
using typename base_type::reference;
4444

4545
// Default constructor.
46-
contiguous_iterator() noexcept : m_current() {}
46+
constexpr contiguous_iterator() noexcept : m_current() {}
4747

4848
// Pointer to iterator constructor.
49-
contiguous_iterator(pointer it) noexcept : m_current(it) {}
49+
constexpr contiguous_iterator(pointer it) noexcept : m_current(it) {}
5050

5151
// As per P2727R4, for contiguous iterator we only need to provide operator*, operator+= and operator-.
52-
reference operator*() const noexcept { return *m_current; }
53-
auto& operator+=(difference_type pos) noexcept {
52+
constexpr reference operator*() const noexcept { return *m_current; }
53+
constexpr auto& operator+=(difference_type pos) noexcept {
5454
m_current += pos;
5555
return *this;
5656
}
57-
difference_type operator-(contiguous_iterator other) const noexcept { return m_current - other.m_current; }
57+
constexpr difference_type operator-(contiguous_iterator other) const noexcept {
58+
return m_current - other.m_current;
59+
}
5860

5961
private:
6062
T* m_current;

include/beman/optional26/optional.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,4 +1152,21 @@ class optional<T&> {
11521152

11531153
} // namespace beman::optional26
11541154

1155+
namespace std {
1156+
template <typename T>
1157+
requires requires(T a) {
1158+
{ std::hash<remove_const_t<T>>{}(a) } -> std::convertible_to<std::size_t>;
1159+
}
1160+
struct hash<beman::optional26::optional<T>> {
1161+
static_assert(!is_reference_v<T>, "hash is not enabled for reference types");
1162+
size_t operator()(const beman::optional26::optional<T>& o) const
1163+
noexcept(noexcept(hash<remove_const_t<T>>{}(*o))) {
1164+
if (o) {
1165+
return std::hash<std::remove_const_t<T>>{}(*o);
1166+
} else {
1167+
return 0;
1168+
}
1169+
}
1170+
};
1171+
} // namespace std
11551172
#endif // BEMAN_OPTIONAL26_OPTIONAL_HPP

src/beman/optional26/tests/detail/iterator.t.cpp

Lines changed: 90 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,27 @@
1010
#include <tests/test_types.hpp>
1111

1212
#include <concepts>
13+
#include <cstdlib>
1314
#include <type_traits>
1415
#include <set>
1516
#include <vector>
1617

17-
namespace beman::optional26::test {
18+
#define CONSTEXPR_EXPECT_EQ(val1, val2) \
19+
if (::std::is_constant_evaluated()) { \
20+
if (!((val1) == (val2))) { \
21+
::std::abort(); \
22+
} \
23+
} else \
24+
EXPECT_EQ(val1, val2)
25+
26+
namespace beman::optional26::tests {
1827

1928
// Dummy containers helper.
2029
struct container {};
2130

22-
} // namespace beman::optional26::test
31+
} // namespace beman::optional26::tests
2332

24-
using namespace beman::optional26::test;
33+
using namespace beman::optional26::tests;
2534

2635
TEST(IteratorTest, IteratorConcepts) {
2736
const auto test = [](auto&& it) {
@@ -53,88 +62,104 @@ TEST(IteratorTest, IteratorConcepts) {
5362
}
5463

5564
TEST(IteratorTest, DereferenceOperator) {
56-
std::vector<int> v{10, 20, 30, 40, 50};
57-
auto it = beman::optional26::detail::contiguous_iterator<int, decltype(v)>{v.data()};
65+
auto lambda = [&] {
66+
std::vector<int> v{10, 20, 30, 40, 50};
67+
auto it = beman::optional26::detail::contiguous_iterator<int, decltype(v)>{v.data()};
5868

59-
EXPECT_EQ(*it, 10);
60-
*it = 100;
61-
EXPECT_EQ(*it, 100);
69+
CONSTEXPR_EXPECT_EQ(*it, 10);
70+
*it = 100;
71+
CONSTEXPR_EXPECT_EQ(*it, 100);
6272

63-
it += 2;
64-
EXPECT_EQ(*it, 30);
73+
it += 2;
74+
CONSTEXPR_EXPECT_EQ(*it, 30);
6575

66-
*it = 300;
67-
EXPECT_EQ(*it, 300);
76+
*it = 300;
77+
CONSTEXPR_EXPECT_EQ(*it, 300);
78+
};
79+
static_assert((lambda(), true));
80+
lambda();
6881
}
6982

7083
TEST(IteratorTest, ForwardIterator) {
71-
std::vector<int> v{10, 20, 30, 40, 50};
72-
const std::vector<int> cv{10, 20, 30, 40, 50};
84+
auto lambda = [&] {
85+
std::vector<int> v{10, 20, 30, 40, 50};
86+
const std::vector<int> cv{10, 20, 30, 40, 50};
7387

74-
const auto test = [](auto&& it) {
75-
EXPECT_EQ(*it, 10);
88+
const auto test = [](auto&& it) {
89+
CONSTEXPR_EXPECT_EQ(*it, 10);
7690

77-
++it; // prefixed increment
78-
EXPECT_EQ(*it, 20);
91+
++it; // prefixed increment
92+
CONSTEXPR_EXPECT_EQ(*it, 20);
7993

80-
it++; // postfixed increment
81-
EXPECT_EQ(*it, 30);
94+
it++; // postfixed increment
95+
CONSTEXPR_EXPECT_EQ(*it, 30);
8296

83-
it++;
84-
EXPECT_EQ(*it, 40);
97+
it++;
98+
CONSTEXPR_EXPECT_EQ(*it, 40);
8599

86-
++it;
87-
EXPECT_EQ(*it, 50);
88-
};
100+
++it;
101+
CONSTEXPR_EXPECT_EQ(*it, 50);
102+
};
89103

90-
test(beman::optional26::detail::contiguous_iterator<int, decltype(v)>{v.data()});
91-
test(beman::optional26::detail::contiguous_iterator<const int, decltype(v)>{cv.data()});
104+
test(beman::optional26::detail::contiguous_iterator<int, decltype(v)>{v.data()});
105+
test(beman::optional26::detail::contiguous_iterator<const int, decltype(v)>{cv.data()});
106+
};
107+
static_assert((lambda(), true));
108+
lambda();
92109
}
93110

94111
TEST(IteratorTest, BidirectionalIterator) {
95-
std::vector<int> v{10, 20, 30, 40, 50};
96-
const std::vector<int> cv{10, 20, 30, 40, 50};
97-
const auto test = [](auto&& it) {
98-
it++;
99-
it++;
100-
EXPECT_EQ(*it, 30);
101-
102-
--it; // prefixed decrement
103-
EXPECT_EQ(*it, 20);
104-
105-
it--; // postfixed decrement
106-
EXPECT_EQ(*it, 10);
112+
auto lambda = [&] {
113+
std::vector<int> v{10, 20, 30, 40, 50};
114+
const std::vector<int> cv{10, 20, 30, 40, 50};
115+
const auto test = [](auto&& it) {
116+
it++;
117+
it++;
118+
CONSTEXPR_EXPECT_EQ(*it, 30);
119+
120+
--it; // prefixed decrement
121+
CONSTEXPR_EXPECT_EQ(*it, 20);
122+
123+
it--; // postfixed decrement
124+
CONSTEXPR_EXPECT_EQ(*it, 10);
125+
};
126+
127+
test(beman::optional26::detail::contiguous_iterator<int, decltype(v)>{v.data()});
128+
test(beman::optional26::detail::contiguous_iterator<const int, decltype(v)>{cv.data()});
107129
};
108-
109-
test(beman::optional26::detail::contiguous_iterator<int, decltype(v)>{v.data()});
110-
test(beman::optional26::detail::contiguous_iterator<const int, decltype(v)>{cv.data()});
130+
static_assert((lambda(), true));
131+
lambda();
111132
}
112133

113134
TEST(IteratorTest, RandomAccessIterator) {
114-
std::vector<int> v{10, 20, 30, 40, 50};
115-
const std::vector<int> cv{10, 20, 30, 40, 50};
116-
const auto test = [](auto&& it) {
117-
EXPECT_EQ(it[0], 10);
118-
EXPECT_EQ(it[1], 20);
119-
EXPECT_EQ(it[2], 30);
120-
EXPECT_EQ(it[3], 40);
121-
EXPECT_EQ(it[4], 50);
122-
123-
it += 2;
124-
EXPECT_EQ(*it, 30);
125-
126-
it -= 1;
127-
EXPECT_EQ(*it, 20);
128-
129-
it = it + 2;
130-
EXPECT_EQ(*it, 40);
131-
132-
it = it - 1;
133-
EXPECT_EQ(*it, 30);
135+
auto lambda = [&] {
136+
std::vector<int> v{10, 20, 30, 40, 50};
137+
const std::vector<int> cv{10, 20, 30, 40, 50};
138+
const auto test = [](auto&& it) {
139+
CONSTEXPR_EXPECT_EQ(it[0], 10);
140+
CONSTEXPR_EXPECT_EQ(it[1], 20);
141+
CONSTEXPR_EXPECT_EQ(it[2], 30);
142+
CONSTEXPR_EXPECT_EQ(it[3], 40);
143+
CONSTEXPR_EXPECT_EQ(it[4], 50);
144+
145+
it += 2;
146+
CONSTEXPR_EXPECT_EQ(*it, 30);
147+
148+
it -= 1;
149+
CONSTEXPR_EXPECT_EQ(*it, 20);
150+
151+
it = it + 2;
152+
CONSTEXPR_EXPECT_EQ(*it, 40);
153+
154+
it = it - 1;
155+
CONSTEXPR_EXPECT_EQ(*it, 30);
156+
};
157+
158+
test(beman::optional26::detail::contiguous_iterator<int, decltype(v)>{v.data()});
159+
test(beman::optional26::detail::contiguous_iterator<const int, decltype(v)>{cv.data()});
134160
};
135-
136-
test(beman::optional26::detail::contiguous_iterator<int, decltype(v)>{v.data()});
137-
test(beman::optional26::detail::contiguous_iterator<const int, decltype(v)>{cv.data()});
161+
static_assert((lambda(), true));
162+
lambda();
138163
}
139164

140165
TEST(IteratorTest, ContainerType) {

src/beman/optional26/tests/optional.t.cpp

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <functional>
1111
#include <ranges>
1212
#include <tuple>
13+
#include <algorithm>
1314

1415
#include <gtest/gtest.h>
1516

@@ -596,7 +597,7 @@ TEST(OptionalTest, RangeTest) {
596597
}
597598
}
598599

599-
TEST(ViewMaybeTest, Constructors) {
600+
TEST(OptionalTest, RangeConstructors) {
600601
std::ranges::single_view<std::optional<int>> s;
601602
std::ranges::single_view<std::optional<int>> s2{s};
602603
std::ranges::single_view<std::optional<int>> s3{std::optional<int>{}};
@@ -610,7 +611,7 @@ TEST(ViewMaybeTest, Constructors) {
610611
std::ignore = n3;
611612
}
612613

613-
TEST(ViewMaybeTest, ConceptCheckRef) {
614+
TEST(OptionalTest, ConceptCheckRef) {
614615
static_assert(std::ranges::range<beman::optional26::optional<int&>>);
615616
static_assert(std::ranges::view<beman::optional26::optional<int&>>);
616617
static_assert(std::ranges::input_range<beman::optional26::optional<int&>>);
@@ -646,7 +647,7 @@ TEST(ViewMaybeTest, ConceptCheckRef) {
646647
static_assert(std::ranges::random_access_range<beman::optional26::optional<ref>>);
647648
}
648649

649-
TEST(ViewMaybeTest, BreathingTest) {
650+
TEST(OptionalTest, BreathingTest) {
650651
beman::optional26::optional<int> m;
651652
beman::optional26::optional<int> m1{1};
652653

@@ -664,7 +665,7 @@ TEST(ViewMaybeTest, BreathingTest) {
664665
ASSERT_EQ(*std::begin(d0), 1.0);
665666
}
666667

667-
TEST(ViewMaybeTest, BreathingTestRef) {
668+
TEST(OptionalTest, BreathingTestRef) {
668669
beman::optional26::optional<int&> m;
669670

670671
int one = 1;
@@ -683,7 +684,7 @@ TEST(ViewMaybeTest, BreathingTestRef) {
683684
ASSERT_EQ(*std::begin(d0), 1.0);
684685
}
685686

686-
TEST(ViewMaybe, CompTest) {
687+
TEST(OptionalTest, CompTest) {
687688
beman::optional26::optional<int> m;
688689
beman::optional26::optional<int> m0{0};
689690
beman::optional26::optional<int> m1{1};
@@ -703,7 +704,7 @@ TEST(ViewMaybe, CompTest) {
703704
ASSERT_TRUE(m1 <= m1a);
704705
}
705706

706-
TEST(ViewMaybe, CompTestRef) {
707+
TEST(OptionalTest, CompTestRef) {
707708
beman::optional26::optional<int&> m;
708709
int zero = 0;
709710
int one = 1;
@@ -743,7 +744,7 @@ inline constexpr auto yield_if = []<class T>(bool b, T x) {
743744
return b ? beman::optional26::optional<T>{std::move(x)} : beman::optional26::nullopt;
744745
};
745746

746-
TEST(ViewMaybeTest, PythTripleTest) {
747+
TEST(OptionalTest, PythTripleTest) {
747748
using std::views::iota;
748749
auto triples = and_then(iota(1), [](int z) {
749750
return and_then(iota(1, z + 1), [=](int x) {
@@ -757,7 +758,7 @@ TEST(ViewMaybeTest, PythTripleTest) {
757758

758759
using namespace beman;
759760

760-
TEST(ViewMaybeTest, ValueBase) {
761+
TEST(OptionalTest, ValueBase) {
761762
int i = 7;
762763
beman::optional26::optional<int> v1{};
763764

@@ -769,7 +770,7 @@ TEST(ViewMaybeTest, ValueBase) {
769770
ASSERT_EQ(i, 7);
770771
}
771772

772-
TEST(ViewMaybeTest, RefWrapper) {
773+
TEST(OptionalTest, RefWrapper) {
773774
int i = 7;
774775

775776
beman::optional26::optional<int> v2{std::ref(i)};
@@ -778,7 +779,7 @@ TEST(ViewMaybeTest, RefWrapper) {
778779
ASSERT_EQ(i, 7);
779780
}
780781

781-
TEST(ViewMaybeTest, ValueNonDefaultConstruct) {
782+
TEST(OptionalTest, ValueNonDefaultConstruct) {
782783
using beman::optional26::tests::int_ctor;
783784
int_ctor i = 7;
784785
beman::optional26::optional<int_ctor> v1{};
@@ -787,7 +788,7 @@ TEST(ViewMaybeTest, ValueNonDefaultConstruct) {
787788
std::ignore = v2;
788789
}
789790

790-
TEST(ViewMaybeTest, RefBase) {
791+
TEST(OptionalTest, RefBase) {
791792
int i = 7;
792793
beman::optional26::optional<int&> v1{};
793794
// ASSERT_TRUE(v1.size() == 0);
@@ -820,3 +821,25 @@ TEST(ViewMaybeTest, RefBase) {
820821
}
821822
ASSERT_EQ(s, 9);
822823
}
824+
825+
TEST(OptionalTest, HashTest) {
826+
beman::optional26::optional<int> o1 = beman::optional26::nullopt;
827+
beman::optional26::optional<int> o2 = beman::optional26::nullopt;
828+
beman::optional26::optional<int> o3 = 42;
829+
beman::optional26::optional<int> o4 = 42;
830+
831+
auto h1 = std::hash<beman::optional26::optional<int>>{}(o1);
832+
auto h2 = std::hash<beman::optional26::optional<int>>{}(o2);
833+
auto h3 = std::hash<beman::optional26::optional<int>>{}(o3);
834+
auto h4 = std::hash<beman::optional26::optional<int>>{}(o4);
835+
836+
EXPECT_EQ(h1, h2);
837+
EXPECT_EQ(h3, h4);
838+
EXPECT_NE(h1, h3);
839+
840+
for(int i : std::views::iota(0, 1000)) {
841+
auto h1 = std::hash<beman::optional26::optional<int>>{}(i);
842+
auto h2 = std::hash<int>{}(i);
843+
EXPECT_EQ(h1, h2);
844+
}
845+
}

0 commit comments

Comments
 (0)