Some improvements to the nullable interface

This commit is contained in:
Jeremy Rifkin 2025-02-01 19:10:19 -06:00
parent 248ad447b1
commit 85be7c32a4
No known key found for this signature in database
GPG Key ID: 19AA8270105E8EB4
2 changed files with 26 additions and 15 deletions

View File

@ -95,37 +95,42 @@ namespace cpptrace {
// use. // use.
template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0> template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
struct nullable { struct nullable {
T raw_value; T raw_value = null_value();
nullable& operator=(T value) { constexpr nullable() noexcept = default;
constexpr nullable(T value) noexcept : raw_value(value) {}
constexpr nullable& operator=(T value) noexcept {
raw_value = value; raw_value = value;
return *this; return *this;
} }
bool has_value() const noexcept { constexpr bool has_value() const noexcept {
return raw_value != (std::numeric_limits<T>::max)(); return raw_value != null_value();
} }
T& value() noexcept { constexpr T& value() noexcept {
return raw_value; return raw_value;
} }
const T& value() const noexcept { constexpr const T& value() const noexcept {
return raw_value; return raw_value;
} }
T value_or(T alternative) const noexcept { constexpr T value_or(T alternative) const noexcept {
return has_value() ? raw_value : alternative; return has_value() ? raw_value : alternative;
} }
void swap(nullable& other) noexcept { constexpr void swap(nullable& other) noexcept {
std::swap(raw_value, other.raw_value); std::swap(raw_value, other.raw_value);
} }
void reset() noexcept { constexpr void reset() noexcept {
raw_value = (std::numeric_limits<T>::max)(); raw_value = (std::numeric_limits<T>::max)();
} }
bool operator==(const nullable& other) const noexcept { constexpr bool operator==(const nullable& other) const noexcept {
return raw_value == other.raw_value; return raw_value == other.raw_value;
} }
bool operator!=(const nullable& other) const noexcept { constexpr bool operator!=(const nullable& other) const noexcept {
return raw_value != other.raw_value; return raw_value != other.raw_value;
} }
constexpr static T null_value() noexcept {
return (std::numeric_limits<T>::max)();
}
constexpr static nullable null() noexcept { constexpr static nullable null() noexcept {
return { (std::numeric_limits<T>::max)() }; return { null_value() };
} }
}; };

View File

@ -13,20 +13,26 @@ TEST(NullableTest, Basic) {
nullable<std::uint32_t> a{12}; nullable<std::uint32_t> a{12};
EXPECT_EQ(a.value(), 12); EXPECT_EQ(a.value(), 12);
EXPECT_EQ(a.raw_value, 12); EXPECT_EQ(a.raw_value, 12);
// TODO: = nullable<std::uint32_t> b = 20;
EXPECT_EQ(b.value(), 20);
} }
TEST(NullableTest, Null) { TEST(NullableTest, Null) {
auto a = nullable<std::uint32_t>::null(); auto a = nullable<std::uint32_t>::null();
EXPECT_FALSE(a.has_value()); EXPECT_FALSE(a.has_value());
EXPECT_EQ(a.raw_value, (std::numeric_limits<std::uint32_t>::max)()); EXPECT_EQ(a.raw_value, (std::numeric_limits<std::uint32_t>::max)());
// TODO: default construct nullable<std::uint32_t> b;
EXPECT_FALSE(b.has_value());
EXPECT_EQ(b.raw_value, nullable<std::uint32_t>::null_value());
} }
TEST(NullableTest, Assignment) { TEST(NullableTest, Assignment) {
nullable<std::uint32_t> a; nullable<std::uint32_t> a;
a = 12; a = 12;
EXPECT_EQ(a.value(), 12); EXPECT_EQ(a.value(), 12);
nullable<std::uint32_t> b = 20;
a = b;
EXPECT_EQ(a.value(), 20);
} }
TEST(NullableTest, Reset) { TEST(NullableTest, Reset) {
@ -49,7 +55,7 @@ TEST(NullableTest, Comparison) {
TEST(NullableTest, Swap) { TEST(NullableTest, Swap) {
auto a = nullable<std::uint32_t>::null(); auto a = nullable<std::uint32_t>::null();
nullable<std::uint32_t> b{12}; nullable<std::uint32_t> b = 12;
EXPECT_FALSE(a.has_value()); EXPECT_FALSE(a.has_value());
EXPECT_EQ(b.value(), 12); EXPECT_EQ(b.value(), 12);
a.swap(b); a.swap(b);