FreeTensor
Loading...
Searching...
No Matches
lazy.h
Go to the documentation of this file.
1#ifndef FREE_TENSOR_LAZY_H
2#define FREE_TENSOR_LAZY_H
3
4#include <functional>
5#include <memory>
6#include <mutex>
7#include <optional>
8#include <type_traits>
9
10namespace freetensor {
11
12template <typename T> class Lazy {
13 struct LazyData {
14 std::optional<T> container_;
15 std::function<T()> delayedInit_;
16 std::once_flag onceFlag_;
17 };
18
19 // Although we deleted copy constructor and copy assignment operator, we
20 // still want to use the move constructor and move assignment operator, but
21 // std::once_flag is not movable. So we use std::unique_ptr to store
22 // LazyData.
23 std::unique_ptr<LazyData> data_ = std::make_unique<LazyData>();
24
25 public:
26 const T &operator*() {
27 std::call_once(data_->onceFlag_,
28 [&] { data_->container_ = data_->delayedInit_(); });
29 return data_->container_.value();
30 }
31
32 const T *operator->() { return &(this->operator*()); }
33
34 template <typename F> Lazy(F delayedInit) {
35 data_->delayedInit_ = delayedInit;
36 }
37
38 // We want to keep only one copy of LazyData. Otherwise, LazyData might be
39 // re-initialized multiple times.
40 //
41 // A bad example:
42 //
43 // ```
44 // a = Lazy(...)
45 // for (...) { auto b = a; *b; } // re-initialized
46 // ```
47 //
48 // A good example:
49 //
50 // ```
51 // a = Lazy(...)
52 // for (...) { auto &b = a; *b; } // initialized only once
53 // ```
54 Lazy(const Lazy &) = delete;
55 Lazy &operator=(const Lazy &) = delete;
56};
57
58template <typename F>
60
61#define LAZY(expr) (Lazy([&]() { return (expr); }))
62
63} // namespace freetensor
64
65#endif // FREE_TENSOR_LAZY_H
Definition: lazy.h:12
const T * operator->()
Definition: lazy.h:32
const T & operator*()
Definition: lazy.h:26
Lazy(const Lazy &)=delete
Lazy(F delayedInit)
Definition: lazy.h:34
Lazy & operator=(const Lazy &)=delete
Definition: allocator.h:9