blob: 495a24f830f3a2ad07ce71d4372ded6754507199 [file] [log] [blame]
Corentin Wallez2089adc2020-11-12 11:47:59 +00001// Copyright 2020 The Dawn Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef COMMON_REFBASE_H_
16#define COMMON_REFBASE_H_
17
Corentin Wallezd98e8b72020-11-17 11:35:11 +000018#include "common/Assert.h"
Corentin Wallez2089adc2020-11-12 11:47:59 +000019#include "common/Compiler.h"
20
21#include <type_traits>
22
23// A common class for various smart-pointers acting on referenceable/releasable pointer-like
24// objects. Logic for each specialization can be customized using a Traits type that looks
25// like the following:
26//
27// struct {
28// static constexpr T kNullValue = ...;
29// static void Reference(T value) { ... }
30// static void Release(T value) { ... }
31// };
32//
33// RefBase supports
34template <typename T, typename Traits>
35class RefBase {
36 private:
37 static constexpr T kNullValue = Traits::kNullValue;
38
39 public:
40 // Default constructor and destructor.
41 RefBase() : mValue(kNullValue) {
42 }
43
44 ~RefBase() {
45 Release();
46 mValue = kNullValue;
47 }
48
49 // Constructors from nullptr.
50 constexpr RefBase(std::nullptr_t) : RefBase() {
51 }
52
53 RefBase<T, Traits>& operator=(std::nullptr_t) {
54 Release();
55 mValue = kNullValue;
56 return *this;
57 }
58
59 // Constructors from a value T.
60 RefBase(T value) : mValue(value) {
61 Reference();
62 }
63
64 RefBase<T, Traits>& operator=(const T& value) {
65 mValue = value;
66 Reference();
67 return *this;
68 }
69
70 // Constructors from a RefBase<T>
71 RefBase(const RefBase<T, Traits>& other) : mValue(other.mValue) {
72 Reference();
73 }
74
75 RefBase<T, Traits>& operator=(const RefBase<T, Traits>& other) {
76 if (&other != this) {
77 other.Reference();
78 Release();
79 mValue = other.mValue;
80 }
81
82 return *this;
83 }
84
85 RefBase(RefBase<T, Traits>&& other) {
86 mValue = other.mValue;
87 other.mValue = kNullValue;
88 }
89
90 RefBase<T, Traits>& operator=(RefBase<T, Traits>&& other) {
91 if (&other != this) {
92 Release();
93 mValue = other.mValue;
94 other.mValue = kNullValue;
95 }
96
97 return *this;
98 }
99
100 // Constructors from a RefBase<U>. Note that in the *-assignment operators this cannot be the
101 // same as `other` because overload resolution rules would have chosen the *-assignement
102 // operators defined with `other` == RefBase<T, Traits>.
103 template <typename U, typename UTraits, typename = typename std::is_convertible<U, T>::type>
104 RefBase(const RefBase<U, UTraits>& other) : mValue(other.mValue) {
105 Reference();
106 }
107
108 template <typename U, typename UTraits, typename = typename std::is_convertible<U, T>::type>
109 RefBase<T, Traits>& operator=(const RefBase<U, UTraits>& other) {
110 other.Reference();
111 Release();
112 mValue = other.mValue;
113 return *this;
114 }
115
116 template <typename U, typename UTraits, typename = typename std::is_convertible<U, T>::type>
117 RefBase(RefBase<U, UTraits>&& other) {
118 mValue = other.Detach();
119 }
120
121 template <typename U, typename UTraits, typename = typename std::is_convertible<U, T>::type>
122 RefBase<T, Traits>& operator=(RefBase<U, UTraits>&& other) {
123 Release();
124 mValue = other.Detach();
125 return *this;
126 }
127
128 // Comparison operators.
129 bool operator==(const T& other) const {
130 return mValue == other;
131 }
132
133 bool operator!=(const T& other) const {
134 return mValue != other;
135 }
136
Corentin Wallez2089adc2020-11-12 11:47:59 +0000137 const T operator->() const {
138 return mValue;
139 }
140 T operator->() {
141 return mValue;
142 }
143
144 // Smart pointer methods.
145 const T& Get() const {
146 return mValue;
147 }
148 T& Get() {
149 return mValue;
150 }
151
152 T Detach() DAWN_NO_DISCARD {
153 T value = mValue;
154 mValue = kNullValue;
155 return value;
156 }
157
Corentin Wallez0055d952020-11-16 23:07:56 +0000158 void Acquire(T value) {
159 Release();
160 mValue = value;
161 }
162
Corentin Wallezd98e8b72020-11-17 11:35:11 +0000163 T* InitializeInto() DAWN_NO_DISCARD {
164 ASSERT(mValue == kNullValue);
165 return &mValue;
166 }
167
Corentin Wallez2089adc2020-11-12 11:47:59 +0000168 private:
169 // Friend is needed so that instances of RefBase<U> can call Reference and Release on
170 // RefBase<T>.
171 template <typename U, typename UTraits>
172 friend class RefBase;
173
174 void Reference() const {
175 if (mValue != kNullValue) {
176 Traits::Reference(mValue);
177 }
178 }
179 void Release() const {
180 if (mValue != kNullValue) {
181 Traits::Release(mValue);
182 }
183 }
184
185 T mValue;
186};
187
188#endif // COMMON_REFBASE_H_