Made Lazy<T> copyable

This commit is contained in:
Daniel Wolf 2016-07-20 20:16:23 +02:00
parent 17b43ad205
commit 5198ee9230
2 changed files with 38 additions and 10 deletions

View File

@ -2,27 +2,38 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
// Class template for lazy initialization.
// Copies use reference semantics.
template<typename T> template<typename T>
class Lazy { class Lazy {
// Shared state between copies
struct State {
std::function<T()> createValue;
std::once_flag initialized;
std::unique_ptr<T> value;
};
public: public:
using value_type = T; using value_type = T;
explicit Lazy(std::function<T()> createValue) : Lazy() = default;
createValue(createValue)
{} explicit Lazy(std::function<T()> createValue) {
state->createValue = createValue;
}
explicit operator bool() const { explicit operator bool() const {
return static_cast<bool>(_value); return static_cast<bool>(state->value);
} }
T& value() { T& value() {
init(); init();
return *_value; return *state->value;
} }
const T& value() const { const T& value() const {
init(); init();
return *_value; return *state->value;
} }
T* operator->() { T* operator->() {
@ -40,12 +51,11 @@ public:
const T& operator*() const { const T& operator*() const {
return value(); return value();
} }
private: private:
void init() const { void init() const {
std::call_once(initialized, [&] { _value = std::make_unique<T>(createValue()); }); std::call_once(state->initialized, [&] { state->value = std::make_unique<T>(state->createValue()); });
} }
std::function<T()> createValue; std::shared_ptr<State> state = std::make_shared<State>();
mutable std::once_flag initialized;
mutable std::unique_ptr<T> _value;
}; };

View File

@ -41,6 +41,24 @@ TEST(Lazy, constUsage) {
EXPECT_TRUE(static_cast<bool>(lazy)); EXPECT_TRUE(static_cast<bool>(lazy));
} }
TEST(Lazy, copying) {
Lazy<Foo> a;
int counter = 0;
auto createValue = [&] { return counter++; };
Lazy<Foo> b(createValue);
a = b;
EXPECT_EQ(0, counter);
EXPECT_FALSE(static_cast<bool>(a));
EXPECT_FALSE(static_cast<bool>(b));
EXPECT_EQ(0, a->value);
EXPECT_EQ(1, counter);
EXPECT_TRUE(static_cast<bool>(a));
EXPECT_TRUE(static_cast<bool>(b));
EXPECT_EQ(0, b->value);
Lazy<Foo> c(createValue);
EXPECT_EQ(1, c->value);
}
using Expensive = Foo; using Expensive = Foo;
#define member value; #define member value;