1 //===-- include/flang/Common/reference-counted.h ----------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef FORTRAN_COMMON_REFERENCE_COUNTED_H_
10 #define FORTRAN_COMMON_REFERENCE_COUNTED_H_
11 
12 // A class template of smart pointers to objects with their own
13 // reference counting object lifetimes that's lighter weight
14 // than std::shared_ptr<>.  Not thread-safe.
15 
16 namespace Fortran::common {
17 
18 // A base class for reference-counted objects.  Must be public.
19 template <typename A> class ReferenceCounted {
20 public:
ReferenceCounted()21   ReferenceCounted() {}
references()22   int references() const { return references_; }
TakeReference()23   void TakeReference() { ++references_; }
DropReference()24   void DropReference() {
25     if (--references_ == 0) {
26       delete static_cast<A *>(this);
27     }
28   }
29 
30 private:
31   int references_{0};
32 };
33 
34 // A reference to a reference-counted object.
35 template <typename A> class CountedReference {
36 public:
37   using type = A;
CountedReference()38   CountedReference() {}
CountedReference(type * m)39   CountedReference(type *m) : p_{m} { Take(); }
CountedReference(const CountedReference & c)40   CountedReference(const CountedReference &c) : p_{c.p_} { Take(); }
CountedReference(CountedReference && c)41   CountedReference(CountedReference &&c) : p_{c.p_} { c.p_ = nullptr; }
42   CountedReference &operator=(const CountedReference &c) {
43     c.Take();
44     Drop();
45     p_ = c.p_;
46     return *this;
47   }
48   CountedReference &operator=(CountedReference &&c) {
49     A *p{c.p_};
50     c.p_ = nullptr;
51     Drop();
52     p_ = p;
53     return *this;
54   }
~CountedReference()55   ~CountedReference() { Drop(); }
56   operator bool() const { return p_ != nullptr; }
get()57   type *get() const { return p_; }
58   type &operator*() const { return *p_; }
59   type *operator->() const { return p_; }
60 
61 private:
Take()62   void Take() const {
63     if (p_) {
64       p_->TakeReference();
65     }
66   }
Drop()67   void Drop() {
68     if (p_) {
69       p_->DropReference();
70       p_ = nullptr;
71     }
72   }
73 
74   type *p_{nullptr};
75 };
76 } // namespace Fortran::common
77 #endif // FORTRAN_COMMON_REFERENCE_COUNTED_H_
78