FreeTensor
Loading...
Searching...
No Matches
sub_tree.h
Go to the documentation of this file.
1#ifndef FREE_TENSOR_SUB_TREE_H
2#define FREE_TENSOR_SUB_TREE_H
3
4#include <atomic>
5#include <vector>
6
7#include <ref.h>
8
9namespace freetensor {
10
11class ASTPart;
12
20struct ChildOf {
22};
23
28#define DEFINE_AST_PART_ACCESS(part) \
29 protected: \
30 part() = default; /* Must be constructed in Ref */ \
31 \
32 friend class Allocator<part>;
33
50class ASTPart : public EnableSelf<ASTPart> {
52
53 Weak<ASTPart> parent_;
54
55 protected:
56 size_t hash_ = ~0ull;
57 std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
58
59 void lock() {
60 while (lock_.test_and_set(std::memory_order_acquire)) {
61 // spin
62 }
63 }
64
65 void unlock() { lock_.clear(std::memory_order_release); }
66
67 virtual void compHash() = 0;
68 void resetHash();
69
70 public:
71 virtual ~ASTPart() {}
72
73 // Construct a new part using another part. The new part will not initially
74 // have a parent, and the other part will keep its parent
75 ASTPart(ASTPart &&other) {}
76 ASTPart(const ASTPart &other) {}
77
78 // Assign the other part to the current part, but the parent of the current
79 // part will still be its parent
80 ASTPart &operator=(ASTPart &&) { return *this; }
81 ASTPart &operator=(const ASTPart &) { return *this; }
82
84 lock();
85 if (parent_.isValid()) {
86 unlock();
87 return false;
88 } else {
89 parent_ = parent;
90 unlock();
91 return true;
92 }
93 }
94 void resetParent() {
95 lock();
96 parent_ = nullptr;
97 unlock();
98 }
99 Ref<ASTPart> parent() const { return parent_.lock(); }
100 bool isSubTree() const { return parent_.isValid(); }
101
107 int depth() const;
108
117 virtual void modifiedHook() { resetHash(); }
118
119 size_t hash();
120
121 virtual bool isAST() const { return false; };
122};
123
125
134template <class T, NullPolicy POLICY = NullPolicy::NotNull> class SubTree {
135 Ref<T> obj_;
136
141 ASTPart *parent_ = nullptr;
142
143 template <class, NullPolicy> friend class SubTree;
144
145 private:
146 void abandon() {
147 if (obj_.isValid()) {
148 if (auto p = obj_->parent(); p.isValid()) {
149 p->modifiedHook();
150 }
151 obj_->resetParent();
152 }
153 obj_ = nullptr;
154 }
155
156 void adopt() {
157 if (obj_.isValid() && parent_ != nullptr) {
158 while (!obj_->trySetParent(
159 ((EnableSelf<typename T::Self> *)parent_)->self())) {
160 obj_ = deepCopy(obj_).template as<T>();
161 }
162 }
163 }
164
165 void checkNull() {
166 if (!obj_.isValid() && POLICY == NullPolicy::NotNull) {
167 ERROR("Cannot assign a null Ref to a NotNull SubTree");
168 }
169 }
170
171 public:
172 SubTree(const ChildOf &c) : parent_(c.parent_) {}
173 ~SubTree() { abandon(); }
174
175 SubTree(std::nullptr_t) { ASSERT(POLICY == NullPolicy::Nullable); }
176
177 template <std::derived_from<T> U> SubTree(const Ref<U> &obj) : obj_(obj) {
178 if (obj_.isValid()) {
179 if (obj_->isSubTree()) {
180 obj_ = deepCopy(obj).template as<T>();
181 }
182 ASSERT(!obj_->isSubTree());
183 }
184 checkNull();
185 }
186 template <std::derived_from<T> U> SubTree(Ref<U> &&obj) : obj_(obj) {
187 if (obj_.isValid()) {
188 if (obj_->isSubTree()) {
189 obj_ = deepCopy(obj).template as<T>();
190 }
191 ASSERT(!obj_->isSubTree());
192 }
193 checkNull();
194 }
195
204 : obj_(std::move(other.obj_)), parent_(other.parent_) {
205 other.parent_ = nullptr;
206 checkNull();
207 }
208 template <NullPolicy OTHER_POLICY>
210 : obj_(std::move(other.obj_)), parent_(other.parent_) {
211 other.parent_ = nullptr;
212 checkNull();
213 }
223 explicit SubTree(const SubTree &other) {
224 if (other.obj_.isValid()) {
225 obj_ = deepCopy(other.obj_).template as<T>();
226 ASSERT(!obj_->isSubTree());
227 } else {
228 obj_ = nullptr;
229 }
230 checkNull();
231 }
232 template <NullPolicy OTHER_POLICY>
233 explicit SubTree(const SubTree<T, OTHER_POLICY> &other) {
234 if (other.obj_.isValid()) {
235 obj_ = deepCopy(other.obj_).template as<T>();
236 ASSERT(!obj_->isSubTree());
237 } else {
238 obj_ = nullptr;
239 }
240 checkNull();
241 }
245 abandon();
246 obj_ = std::move(other.obj_);
247 adopt();
248 checkNull();
249 return *this;
250 }
251 template <NullPolicy OTHER_POLICY>
253 abandon();
254 obj_ = std::move(other.obj_);
255 adopt();
256 checkNull();
257 return *this;
258 }
259
260 SubTree &operator=(const SubTree &other) {
261 abandon();
262 if (other.obj_.isValid()) {
263 obj_ = deepCopy(other.obj_).template as<T>();
264 ASSERT(!obj_->isSubTree());
265 adopt();
266 } else {
267 obj_ = nullptr;
268 }
269 checkNull();
270 return *this;
271 }
272 template <NullPolicy OTHER_POLICY>
274 abandon();
275 if (other.obj_.isValid()) {
276 obj_ = deepCopy(other.obj_).template as<T>();
277 ASSERT(!obj_->isSubTree());
278 adopt();
279 } else {
280 obj_ = nullptr;
281 }
282 checkNull();
283 return *this;
284 }
285
286 template <class U>
287 requires std::derived_from<T, U>
288 operator Ref<U>() const {
289 return obj_;
290 }
291
292 T &operator*() const { return *obj_; }
293 T *operator->() const { return obj_.get(); }
294
295 template <class U> Ref<U> as() const { return obj_.template as<U>(); }
296
297 bool isValid() const { return obj_.isValid(); }
298};
299
305template <class T, NullPolicy POLICY = NullPolicy::NotNull> class SubTreeList {
306 std::vector<SubTree<T, POLICY>> objs_;
307
312 ASTPart *parent_ = nullptr;
313
314 template <class, NullPolicy> friend class SubTree;
315
316 public:
317 SubTreeList(const ChildOf &c) : parent_(c.parent_) {}
318
319 template <std::derived_from<T> U>
320 SubTreeList(const std::vector<Ref<U>> &objs) {
321 objs_.reserve(objs.size());
322 for (auto &&item : objs) {
323 SubTree<T, POLICY> newItem = ChildOf{parent_};
324 newItem = item;
325 objs_.emplace_back(std::move(newItem));
326 }
327 }
328 template <std::derived_from<T> U> SubTreeList(std::vector<Ref<U>> &&objs) {
329 objs_.reserve(objs.size());
330 for (auto &&item : objs) {
331 SubTree<T, POLICY> newItem = ChildOf{parent_};
332 newItem = std::move(item);
333 objs_.emplace_back(std::move(newItem));
334 }
335 }
336 template <std::derived_from<T> U>
337 SubTreeList(std::initializer_list<Ref<U>> objs) {
338 objs_.reserve(objs.size());
339 for (auto &&item : objs) {
340 SubTree<T, POLICY> newItem = ChildOf{parent_};
341 newItem = std::move(item);
342 objs_.emplace_back(std::move(newItem));
343 }
344 }
345
354 : objs_(std::move(other.objs_)), parent_(other.parent_) {
355 other.parent_ = nullptr;
356 }
357 template <NullPolicy OTHER_POLICY>
358 SubTreeList(SubTreeList<T, OTHER_POLICY> &&other) : parent_(other.parent_) {
359 objs_.reserve(other.objs_.size());
360 for (auto &&item : other.objs_) {
361 objs_.emplace_back(std::move(item));
362 }
363 other.objs_.clear();
364 other.parent_ = nullptr;
365 }
376 explicit SubTreeList(const SubTreeList &other) {
377 objs_.reserve(other.objs_.size());
378 for (auto &&item : other.objs_) {
379 SubTree<T, POLICY> newItem = ChildOf{parent_};
380 newItem = item;
381 objs_.emplace_back(std::move(newItem));
382 }
383 }
384 template <NullPolicy OTHER_POLICY>
386 objs_.reserve(other.objs_.size());
387 for (auto &&item : other.objs_) {
388 SubTree<T, POLICY> newItem = ChildOf{parent_};
389 newItem = item;
390 objs_.emplace_back(std::move(newItem));
391 }
392 }
396 objs_.clear();
397 objs_.reserve(other.objs_.size());
398 for (auto &&item : other.objs_) {
399 SubTree<T, POLICY> newItem = ChildOf{parent_};
400 newItem = std::move(item);
401 objs_.emplace_back(std::move(newItem));
402 }
403 return *this;
404 }
406 objs_.clear();
407 objs_.reserve(other.objs_.size());
408 for (auto &&item : other.objs_) {
409 SubTree<T, POLICY> newItem = ChildOf{parent_};
410 newItem = item;
411 objs_.emplace_back(std::move(newItem));
412 }
413 return *this;
414 }
415
416 template <NullPolicy OTHER_POLICY>
418 objs_.clear();
419 objs_.reserve(other.objs_.size());
420 for (auto &&item : other.objs_) {
421 SubTree<T, POLICY> newItem = ChildOf{parent_};
422 newItem = std::move(item);
423 objs_.emplace_back(std::move(newItem));
424 }
425 return *this;
426 }
427 template <NullPolicy OTHER_POLICY>
429 objs_.clear();
430 objs_.reserve(other.objs_.size());
431 for (auto &&item : other.objs_) {
432 SubTree<T, POLICY> newItem = ChildOf{parent_};
433 newItem = item;
434 objs_.emplace_back(std::move(newItem));
435 }
436 return *this;
437 }
438
439 SubTreeList &operator=(std::initializer_list<Ref<T>> &&objs) {
440 objs_.clear();
441 objs_.reserve(objs.size());
442 for (auto &&item : objs) {
443 SubTree<T, POLICY> newItem = ChildOf{parent_};
444 newItem = std::move(item);
445 objs_.emplace_back(std::move(newItem));
446 }
447 return *this;
448 }
449
450 template <class U>
451 requires std::derived_from<T, U>
452 operator std::vector<Ref<U>>() const {
453 return std::vector<Ref<U>>(objs_.begin(), objs_.end());
454 }
455
456 auto begin() { return objs_.begin(); }
457 auto begin() const { return objs_.begin(); }
458 auto end() { return objs_.end(); }
459 auto end() const { return objs_.end(); }
460 auto rbegin() { return objs_.rbegin(); }
461 auto rbegin() const { return objs_.rbegin(); }
462 auto rend() { return objs_.rend(); }
463 auto rend() const { return objs_.rend(); }
464 auto size() const { return objs_.size(); }
465 auto empty() const { return objs_.empty(); }
466 template <class U> auto &operator[](U &&i) {
467 return objs_[std::forward<U>(i)];
468 }
469 template <class U> const auto &operator[](U &&i) const {
470 return objs_[std::forward<U>(i)];
471 }
472 template <class U> auto &at(U &&i) { return objs_.at(std::forward<U>(i)); }
473 template <class U> const auto &at(U &&i) const {
474 return objs_.at(std::forward<U>(i));
475 }
476 auto &front() { return objs_.front(); }
477 const auto &front() const { return objs_.front(); }
478 auto &back() { return objs_.back(); }
479 const auto &back() const { return objs_.back(); }
480 template <class U> void emplace_back(U &&x) {
481 objs_.emplace_back(std::forward<U>(x));
482 }
483 template <class U> void push_back(U &&x) {
484 objs_.push_back(std::forward<U>(x));
485 }
486 template <class... U> auto insert(U &&...i) {
487 return objs_.insert(std::forward<U>(i)...);
488 }
489 template <class U> auto erase(U &&i) {
490 return objs_.erase(std::forward<U>(i));
491 }
492 void pop_back() { objs_.pop_back(); }
493 template <class U> void reserve(U &&x) {
494 objs_.reserve(std::forward<U>(x));
495 }
496 void clear() { objs_.clear(); }
497};
498
502Ref<ASTPart> lca(const Ref<ASTPart> &lhs, const Ref<ASTPart> &rhs);
503
504} // namespace freetensor
505
506#endif // FREE_TENSOR_SUB_TREE_H
Definition: sub_tree.h:50
virtual bool isAST() const
Definition: sub_tree.h:121
ASTPart & operator=(ASTPart &&)
Definition: sub_tree.h:80
bool trySetParent(const Ref< ASTPart > &parent)
Definition: sub_tree.h:83
size_t hash()
Definition: sub_tree.cc:13
bool isSubTree() const
Definition: sub_tree.h:100
ASTPart(const ASTPart &other)
Definition: sub_tree.h:76
void resetHash()
Definition: sub_tree.cc:22
ASTPart(ASTPart &&other)
Definition: sub_tree.h:75
ASTPart & operator=(const ASTPart &)
Definition: sub_tree.h:81
virtual ~ASTPart()
Definition: sub_tree.h:71
virtual void compHash()=0
size_t hash_
Definition: sub_tree.h:56
std::atomic_flag lock_
Definition: sub_tree.h:57
void unlock()
Definition: sub_tree.h:65
Ref< ASTPart > parent() const
Definition: sub_tree.h:99
virtual void modifiedHook()
Definition: sub_tree.h:117
void resetParent()
Definition: sub_tree.h:94
void lock()
Definition: sub_tree.h:59
int depth() const
Definition: sub_tree.cc:5
Definition: ref.h:154
Definition: ref.h:24
bool isValid() const
Definition: ref.h:89
T * get() const
Definition: ref.h:101
Definition: sub_tree.h:305
const auto & operator[](U &&i) const
Definition: sub_tree.h:469
auto rbegin()
Definition: sub_tree.h:460
const auto & front() const
Definition: sub_tree.h:477
void clear()
Definition: sub_tree.h:496
auto & at(U &&i)
Definition: sub_tree.h:472
auto erase(U &&i)
Definition: sub_tree.h:489
SubTreeList(std::initializer_list< Ref< U > > objs)
Definition: sub_tree.h:337
auto rend() const
Definition: sub_tree.h:463
void pop_back()
Definition: sub_tree.h:492
void push_back(U &&x)
Definition: sub_tree.h:483
auto & operator[](U &&i)
Definition: sub_tree.h:466
SubTreeList(const SubTreeList &other)
Definition: sub_tree.h:376
auto end() const
Definition: sub_tree.h:459
SubTreeList(const ChildOf &c)
Definition: sub_tree.h:317
void reserve(U &&x)
Definition: sub_tree.h:493
auto begin()
Definition: sub_tree.h:456
SubTreeList & operator=(std::initializer_list< Ref< T > > &&objs)
Definition: sub_tree.h:439
const auto & back() const
Definition: sub_tree.h:479
SubTreeList(std::vector< Ref< U > > &&objs)
Definition: sub_tree.h:328
auto & back()
Definition: sub_tree.h:478
auto empty() const
Definition: sub_tree.h:465
SubTreeList(const std::vector< Ref< U > > &objs)
Definition: sub_tree.h:320
SubTreeList & operator=(const SubTreeList< T, OTHER_POLICY > &other)
Definition: sub_tree.h:428
auto begin() const
Definition: sub_tree.h:457
auto & front()
Definition: sub_tree.h:476
SubTreeList(const SubTreeList< T, OTHER_POLICY > &other)
Definition: sub_tree.h:385
auto end()
Definition: sub_tree.h:458
auto rend()
Definition: sub_tree.h:462
auto size() const
Definition: sub_tree.h:464
auto insert(U &&...i)
Definition: sub_tree.h:486
const auto & at(U &&i) const
Definition: sub_tree.h:473
SubTreeList & operator=(SubTreeList &&other)
Definition: sub_tree.h:395
SubTreeList & operator=(const SubTreeList &other)
Definition: sub_tree.h:405
SubTreeList(SubTreeList &&other)
Definition: sub_tree.h:353
auto rbegin() const
Definition: sub_tree.h:461
void emplace_back(U &&x)
Definition: sub_tree.h:480
SubTreeList(SubTreeList< T, OTHER_POLICY > &&other)
Definition: sub_tree.h:358
SubTreeList & operator=(SubTreeList< T, OTHER_POLICY > &&other)
Definition: sub_tree.h:417
Definition: sub_tree.h:134
~SubTree()
Definition: sub_tree.h:173
Ref< U > as() const
Definition: sub_tree.h:295
bool isValid() const
Definition: sub_tree.h:297
T & operator*() const
Definition: sub_tree.h:292
SubTree(Ref< U > &&obj)
Definition: sub_tree.h:186
SubTree(std::nullptr_t)
Definition: sub_tree.h:175
SubTree & operator=(SubTree &&other)
Definition: sub_tree.h:244
SubTree(const ChildOf &c)
Definition: sub_tree.h:172
SubTree(SubTree< T, OTHER_POLICY > &&other)
Definition: sub_tree.h:209
T * operator->() const
Definition: sub_tree.h:293
SubTree(const SubTree &other)
Definition: sub_tree.h:223
SubTree & operator=(SubTree< T, OTHER_POLICY > &&other)
Definition: sub_tree.h:252
SubTree & operator=(const SubTree &other)
Definition: sub_tree.h:260
SubTree(const SubTree< T, OTHER_POLICY > &other)
Definition: sub_tree.h:233
SubTree & operator=(const SubTree< T, OTHER_POLICY > &other)
Definition: sub_tree.h:273
SubTree(const Ref< U > &obj)
Definition: sub_tree.h:177
SubTree(SubTree &&other)
Definition: sub_tree.h:203
Definition: ref.h:125
Ref< T > lock() const
Definition: ref.h:142
bool isValid() const
Definition: ref.h:140
#define ASSERT(expr)
Definition: except.h:152
#define ERROR(msg)
Definition: except.h:141
Definition: allocator.h:9
auto && lhs
Definition: const_fold.cc:70
Ref< ASTPart > lca(const Ref< ASTPart > &lhs, const Ref< ASTPart > &rhs)
Definition: sub_tree.cc:31
Expr deepCopy(const Expr &op)
Definition: ast.cc:364
auto auto && rhs
Definition: const_fold.cc:70
NullPolicy
Definition: sub_tree.h:124
@ NotNull
Definition: sub_tree.h:124
@ Nullable
Definition: sub_tree.h:124
STL namespace.
Definition: sub_tree.h:20
ASTPart * parent_
Definition: sub_tree.h:21
#define DEFINE_AST_PART_ACCESS(part)
Definition: sub_tree.h:28