Skip to content

Commit 81df279

Browse files
committed
added NanOptional specialisation and improved tests
1 parent b91e596 commit 81df279

File tree

7 files changed

+108
-9
lines changed

7 files changed

+108
-9
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#pragma once
2+
#include "Optional.h"
3+
#include "meta19/nullptr_to.h"
4+
5+
#include <limits> // std::numeric_limits
6+
#include <type_traits> // std::is_invocable_r_v
7+
8+
namespace optional19 {
9+
10+
using meta19::nullptr_to;
11+
12+
/// Specialized packed optional storing a floating point value
13+
/// NaN (not a number) values are treated as not present values
14+
template<class T> requires(std::numeric_limits<T>::has_quiet_NaN) struct Optional<T> {
15+
private:
16+
static constexpr auto nan = std::numeric_limits<T>::quiet_NaN();
17+
static constexpr bool isNan(T v) { return v != v; } // note: Only NaN values are not equal to themself
18+
T m_data{nan};
19+
20+
public:
21+
constexpr Optional() = default;
22+
constexpr Optional(T v) : m_data(v) {}
23+
24+
constexpr explicit operator bool() const { return !isNan(m_data); }
25+
26+
/// @return predicate(value()) if optional is set else return false
27+
template<class F> constexpr auto operator&&(F&& f) const -> bool {
28+
if constexpr (std::is_invocable_r_v<bool, F, T>)
29+
return *this ? f(value()) : false;
30+
else {
31+
return *this ? f : false;
32+
}
33+
}
34+
35+
template<class F> constexpr auto operator||(F&& f) const -> T {
36+
if constexpr (std::is_invocable_r_v<T, F>)
37+
return *this ? value() : f();
38+
else
39+
return *this ? value() : f;
40+
}
41+
42+
template<class F> constexpr auto map(F&& f) const -> decltype(f(*nullptr_to<T>)) {
43+
if (*this) return f(value());
44+
if constexpr (!std::is_void_v<decltype(f(*nullptr_to<T>))>) return {};
45+
}
46+
47+
constexpr auto value() const -> const T& { return m_data; }
48+
constexpr auto amend() -> T& { return m_data; }
49+
};
50+
51+
} // namespace optional19
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include "NanOptional.h"
2+
#include "Optional.equals.h"
3+
#include "Optional.ostream.h"
4+
5+
#include <gtest/gtest.h>
6+
7+
using namespace optional19;
8+
9+
TEST(Optional, double) {
10+
using OptDbl = Optional<double>;
11+
12+
static_assert(sizeof(OptDbl) == sizeof(double));
13+
{
14+
constexpr auto optDbl = OptDbl{};
15+
ASSERT_FALSE(optDbl);
16+
ASSERT_EQ(optDbl, OptDbl{});
17+
18+
EXPECT_DOUBLE_EQ((optDbl || 3.14), 3.14);
19+
20+
constexpr const auto constOpt = optDbl;
21+
ASSERT_FALSE(constOpt);
22+
EXPECT_DOUBLE_EQ(constOpt || 4.14, 4.14);
23+
24+
ASSERT_FALSE(constOpt && [](double v) { return v > 4.14; });
25+
}
26+
{
27+
constexpr auto optDbl = OptDbl{2.3};
28+
constexpr const auto constOpt = optDbl;
29+
ASSERT_TRUE(optDbl);
30+
ASSERT_EQ(constOpt, OptDbl{2.3});
31+
32+
EXPECT_DOUBLE_EQ(optDbl.value(), 2.3);
33+
EXPECT_DOUBLE_EQ(optDbl || 4.2, 2.3);
34+
35+
auto l = constOpt.map([](double v) { return v * 2.0; });
36+
EXPECT_DOUBLE_EQ(l, 2.3 * 2.0);
37+
38+
ASSERT_FALSE(constOpt && [](double v) { return v > 4.2; });
39+
ASSERT_TRUE(constOpt && [](double v) { return v > 0.0; });
40+
}
41+
42+
auto optDbl = OptDbl{};
43+
ASSERT_NE(optDbl, OptDbl{2.3});
44+
optDbl = 2.3;
45+
ASSERT_EQ(optDbl, OptDbl{2.3});
46+
}

src/optional19.lib/optional19/Optional.test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ TEST(Optional, int) {
2727
constexpr auto optInt = OptInt{23};
2828
constexpr const auto constOpt = optInt;
2929
ASSERT_TRUE(optInt);
30-
// ASSERT_EQ(constOpt, 23);
30+
ASSERT_EQ(constOpt, OptInt{23});
3131

3232
ASSERT_EQ(optInt.value(), 23);
3333
ASSERT_EQ(optInt || 42, 23);
@@ -40,7 +40,7 @@ TEST(Optional, int) {
4040
}
4141

4242
auto optInt = OptInt{};
43-
// ASSERT_NE(optInt, 23);
43+
ASSERT_NE(optInt, OptInt{23});
4444
optInt = 23;
45-
// ASSERT_EQ(optInt, 23);
45+
ASSERT_EQ(optInt, OptInt{23});
4646
}

src/optional19.lib/optional19/PackedOptional.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ template<auto makeInvalid> struct PackedOptional {
1616

1717
public:
1818
constexpr PackedOptional() = default;
19-
constexpr PackedOptional(T v) : m_data((T &&) v){};
19+
constexpr PackedOptional(T v) : m_data((T &&) v) {}
2020

2121
constexpr explicit operator bool() const { return !(m_data == makeInvalid()); }
2222

src/optional19.lib/optional19/PackedOptional.test.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ TEST(PackedOptional, defaultOfInt) {
4040
}
4141

4242
auto optInt = OptInt{};
43-
// ASSERT_NE(optInt, 23);
43+
ASSERT_NE(optInt, OptInt{23});
4444
optInt = 23;
45-
// ASSERT_EQ(optInt, 23);
45+
ASSERT_EQ(optInt, OptInt{23});
4646
}
4747

4848
constexpr auto intInvalid() { return -1; }
@@ -68,7 +68,7 @@ TEST(PackedOptional, invalidFunc) {
6868
{
6969
constexpr auto optInt = OptInt{23};
7070
static_assert(optInt);
71-
// static_assert(optInt == 23);
71+
static_assert(optInt == OptInt{23});
7272

7373
static_assert(optInt.value() == 23);
7474
static_assert((optInt || 42) == 23);
@@ -82,9 +82,9 @@ TEST(PackedOptional, invalidFunc) {
8282
}
8383

8484
auto optInt = OptInt{};
85-
// ASSERT_NE(optInt, 23);
85+
ASSERT_NE(optInt, OptInt{23});
8686
optInt = 23;
87-
// ASSERT_EQ(optInt, 23);
87+
ASSERT_EQ(optInt, OptInt{23});
8888
}
8989

9090
TEST(PackedOptional, pointer) {

src/optional19.lib/optional19/optional19.qbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Product {
44
Depends { name: "meta19" }
55

66
files: [
7+
"NanOptional.h",
78
"Optional.equals.h",
89
"Optional.h",
910
"Optional.ostream.h",

src/optional19.lib/optional19/optional19.tests.qbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Application {
1010
Depends { name: "googletest" }
1111

1212
files: [
13+
"NanOptional.test.cpp",
1314
"Optional.test.cpp",
1415
"PackedOptional.test.cpp",
1516
]

0 commit comments

Comments
 (0)