diff --git a/sw/lazy_init.h b/sw/lazy_init.h index 2013f32..3d82ff6 100644 --- a/sw/lazy_init.h +++ b/sw/lazy_init.h @@ -40,5 +40,23 @@ namespace sw ensure_initialized(); return *data_; } + + auto operator->() -> ValueType* + { + ensure_initialized(); + return data_.get(); + } + + auto operator->() const -> ValueType const* + { + ensure_initialized(); + return data_.get(); + } + + template >> + bool operator==(lazy_init const& that) const + { + return operator*() == *that; + } }; } \ No newline at end of file diff --git a/tests/lazy_init_tests.cpp b/tests/lazy_init_tests.cpp index 595170f..af292d2 100644 --- a/tests/lazy_init_tests.cpp +++ b/tests/lazy_init_tests.cpp @@ -13,14 +13,9 @@ concept lazy_init_specialization = std::is_constructible_v && std::is_same_v()), typename T::value_type&> && std::is_same_v()), typename T::value_type const&> - // I'm not sure if this is a bug or a feature, but at least it's documented here: - //!std::is_move_assignable_v && - //!std::is_move_constructible_v && - //!std::is_copy_assignable_v && - //!std::is_copy_constructible_v ; -struct not_default_constructible alignas(16) +struct not_default_constructible { explicit not_default_constructible() = delete; explicit not_default_constructible(int) {} @@ -94,10 +89,65 @@ TEST(LazyInit, StarOperator) } } +struct equality_comparable final +{ + int value; + bool operator==(equality_comparable const&) const = default; +}; + +TEST(LazyInit, ArrowOperator) +{ + for (auto i : std::ranges::iota_view(5, 10)) + { + sw::lazy_init li{ + [&] { + return equality_comparable{i}; + } }; + sw::lazy_init const& const_ref = li; + EXPECT_EQ(li->value, i); + EXPECT_EQ(const_ref->value, i); + } +} + +TEST(LazyInit, CompareEquality) +{ + sw::lazy_init li0{ + [] { + return equality_comparable{0}; + } }; + + sw::lazy_init li1{ + [] { + return equality_comparable{1}; + } }; + sw::lazy_init const& const_ref = li0; + EXPECT_TRUE(li0 == const_ref); + EXPECT_TRUE(li0 != li1); + EXPECT_TRUE(const_ref != li1); + EXPECT_FALSE(li0 == li1); +} + +struct not_equality_comparable final +{ + int value; + bool operator==(equality_comparable const&) const = delete; +}; + +// This test ensures that we don't accidentally require the value type to be equality comparable, +// unless we actually try to compare two values. +TEST(LazyInit, UncomparableClassCanBeConstructed) +{ + sw::lazy_init li{ + [] { + return not_equality_comparable{0}; + } }; + EXPECT_EQ((*li).value, 0); +} + + + // TODO: // Implement operators -// Arrow -// Equality (conditionally) // Spaceship (conditionally) // Ensure thread safety. // Null-check function pointers.