OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #ifndef WEBRTC_BASE_OPTIONAL_H_ | 11 #ifndef WEBRTC_BASE_OPTIONAL_H_ |
12 #define WEBRTC_BASE_OPTIONAL_H_ | 12 #define WEBRTC_BASE_OPTIONAL_H_ |
13 | 13 |
14 #include <algorithm> | 14 #include <algorithm> |
15 #include <memory> | 15 #include <memory> |
16 #include <utility> | 16 #include <utility> |
17 | 17 |
18 #include "webrtc/base/array_view.h" | |
18 #include "webrtc/base/checks.h" | 19 #include "webrtc/base/checks.h" |
20 #include "webrtc/base/sanitizer.h" | |
19 | 21 |
20 namespace rtc { | 22 namespace rtc { |
21 | 23 |
24 namespace internal { | |
25 | |
26 #if RTC_HAS_ASAN | |
27 | |
28 // This is a non-inlined function. The optimizer can't see inside it. | |
29 void* FunctionThatDoesNothingImpl(void*); | |
30 | |
31 template <typename T> | |
32 inline T* FunctionThatDoesNothing(T* x) { | |
33 return reinterpret_cast<T*>( | |
34 FunctionThatDoesNothingImpl(reinterpret_cast<void*>(x))); | |
35 } | |
36 | |
37 #else | |
38 | |
39 template <typename T> | |
40 inline T* FunctionThatDoesNothing(T* x) { return x; } | |
41 | |
42 #endif | |
43 | |
44 } // namespace internal | |
45 | |
22 // Simple std::optional-wannabe. It either contains a T or not. | 46 // Simple std::optional-wannabe. It either contains a T or not. |
23 // | 47 // |
24 // A moved-from Optional<T> may only be destroyed, and assigned to if T allows | 48 // A moved-from Optional<T> may only be destroyed, and assigned to if T allows |
25 // being assigned to after having been moved from. Specifically, you may not | 49 // being assigned to after having been moved from. Specifically, you may not |
26 // assume that it just doesn't contain a value anymore. | 50 // assume that it just doesn't contain a value anymore. |
27 // | 51 // |
28 // Examples of good places to use Optional: | 52 // Examples of good places to use Optional: |
29 // | 53 // |
30 // - As a class or struct member, when the member doesn't always have a value: | 54 // - As a class or struct member, when the member doesn't always have a value: |
31 // struct Prisoner { | 55 // struct Prisoner { |
(...skipping 20 matching lines...) Expand all Loading... | |
52 // Optional<double> when parsing a single number as in the example above | 76 // Optional<double> when parsing a single number as in the example above |
53 // might make sense, but any larger parse job is probably going to need to | 77 // might make sense, but any larger parse job is probably going to need to |
54 // tell the caller what the problem was, not just that there was one. | 78 // tell the caller what the problem was, not just that there was one. |
55 // | 79 // |
56 // TODO(kwiberg): Get rid of this class when the standard library has | 80 // TODO(kwiberg): Get rid of this class when the standard library has |
57 // std::optional (and we're allowed to use it). | 81 // std::optional (and we're allowed to use it). |
58 template <typename T> | 82 template <typename T> |
59 class Optional final { | 83 class Optional final { |
60 public: | 84 public: |
61 // Construct an empty Optional. | 85 // Construct an empty Optional. |
62 Optional() : has_value_(false), empty_('\0') {} | 86 Optional() : has_value_(false), empty_('\0') { |
87 PoisonValue(); | |
88 } | |
63 | 89 |
64 // Construct an Optional that contains a value. | 90 // Construct an Optional that contains a value. |
65 explicit Optional(const T& value) : has_value_(true) { | 91 explicit Optional(const T& value) : has_value_(true) { |
66 new (&value_) T(value); | 92 new (&value_) T(value); |
67 } | 93 } |
68 explicit Optional(T&& value) : has_value_(true) { | 94 explicit Optional(T&& value) : has_value_(true) { |
69 new (&value_) T(std::move(value)); | 95 new (&value_) T(std::move(value)); |
70 } | 96 } |
71 | 97 |
72 // Copy constructor: copies the value from m if it has one. | 98 // Copy constructor: copies the value from m if it has one. |
73 Optional(const Optional& m) : has_value_(m.has_value_) { | 99 Optional(const Optional& m) : has_value_(m.has_value_) { |
74 if (has_value_) | 100 if (has_value_) |
75 new (&value_) T(m.value_); | 101 new (&value_) T(m.value_); |
102 else | |
103 PoisonValue(); | |
76 } | 104 } |
77 | 105 |
78 // Move constructor: if m has a value, moves the value from m, leaving m | 106 // Move constructor: if m has a value, moves the value from m, leaving m |
79 // still in a state where it has a value, but a moved-from one (the | 107 // still in a state where it has a value, but a moved-from one (the |
80 // properties of which depends on T; the only general guarantee is that we | 108 // properties of which depends on T; the only general guarantee is that we |
81 // can destroy m). | 109 // can destroy m). |
82 Optional(Optional&& m) : has_value_(m.has_value_) { | 110 Optional(Optional&& m) : has_value_(m.has_value_) { |
83 if (has_value_) | 111 if (has_value_) |
84 new (&value_) T(std::move(m.value_)); | 112 new (&value_) T(std::move(m.value_)); |
113 else | |
114 PoisonValue(); | |
85 } | 115 } |
86 | 116 |
87 ~Optional() { | 117 ~Optional() { |
88 if (has_value_) | 118 if (has_value_) |
89 value_.~T(); | 119 value_.~T(); |
120 else | |
121 UnpoisonValue(); | |
90 } | 122 } |
91 | 123 |
92 // Copy assignment. Uses T's copy assignment if both sides have a value, T's | 124 // Copy assignment. Uses T's copy assignment if both sides have a value, T's |
93 // copy constructor if only the right-hand side has a value. | 125 // copy constructor if only the right-hand side has a value. |
94 Optional& operator=(const Optional& m) { | 126 Optional& operator=(const Optional& m) { |
95 if (m.has_value_) { | 127 if (m.has_value_) { |
96 if (has_value_) { | 128 if (has_value_) { |
97 value_ = m.value_; // T's copy assignment. | 129 value_ = m.value_; // T's copy assignment. |
98 } else { | 130 } else { |
131 UnpoisonValue(); | |
99 new (&value_) T(m.value_); // T's copy constructor. | 132 new (&value_) T(m.value_); // T's copy constructor. |
100 has_value_ = true; | 133 has_value_ = true; |
101 } | 134 } |
102 } else if (has_value_) { | 135 } else if (has_value_) { |
103 value_.~T(); | 136 value_.~T(); |
104 has_value_ = false; | 137 has_value_ = false; |
138 PoisonValue(); | |
105 } | 139 } |
106 return *this; | 140 return *this; |
107 } | 141 } |
108 | 142 |
109 // Move assignment. Uses T's move assignment if both sides have a value, T's | 143 // Move assignment. Uses T's move assignment if both sides have a value, T's |
110 // move constructor if only the right-hand side has a value. The state of m | 144 // move constructor if only the right-hand side has a value. The state of m |
111 // after it's been moved from is as for the move constructor. | 145 // after it's been moved from is as for the move constructor. |
112 Optional& operator=(Optional&& m) { | 146 Optional& operator=(Optional&& m) { |
113 if (m.has_value_) { | 147 if (m.has_value_) { |
114 if (has_value_) { | 148 if (has_value_) { |
115 value_ = std::move(m.value_); // T's move assignment. | 149 value_ = std::move(m.value_); // T's move assignment. |
116 } else { | 150 } else { |
151 UnpoisonValue(); | |
117 new (&value_) T(std::move(m.value_)); // T's move constructor. | 152 new (&value_) T(std::move(m.value_)); // T's move constructor. |
118 has_value_ = true; | 153 has_value_ = true; |
119 } | 154 } |
120 } else if (has_value_) { | 155 } else if (has_value_) { |
121 value_.~T(); | 156 value_.~T(); |
122 has_value_ = false; | 157 has_value_ = false; |
158 PoisonValue(); | |
123 } | 159 } |
124 return *this; | 160 return *this; |
125 } | 161 } |
126 | 162 |
127 // Swap the values if both m1 and m2 have values; move the value if only one | 163 // Swap the values if both m1 and m2 have values; move the value if only one |
128 // of them has one. | 164 // of them has one. |
129 friend void swap(Optional& m1, Optional& m2) { | 165 friend void swap(Optional& m1, Optional& m2) { |
130 if (m1.has_value_) { | 166 if (m1.has_value_) { |
131 if (m2.has_value_) { | 167 if (m2.has_value_) { |
132 // Both have values: swap. | 168 // Both have values: swap. |
133 using std::swap; | 169 using std::swap; |
134 swap(m1.value_, m2.value_); | 170 swap(m1.value_, m2.value_); |
135 } else { | 171 } else { |
136 // Only m1 has a value: move it to m2. | 172 // Only m1 has a value: move it to m2. |
173 m2.UnpoisonValue(); | |
137 new (&m2.value_) T(std::move(m1.value_)); | 174 new (&m2.value_) T(std::move(m1.value_)); |
138 m1.value_.~T(); // Destroy the moved-from value. | 175 m1.value_.~T(); // Destroy the moved-from value. |
139 m1.has_value_ = false; | 176 m1.has_value_ = false; |
140 m2.has_value_ = true; | 177 m2.has_value_ = true; |
178 m1.PoisonValue(); | |
141 } | 179 } |
142 } else if (m2.has_value_) { | 180 } else if (m2.has_value_) { |
143 // Only m2 has a value: move it to m1. | 181 // Only m2 has a value: move it to m1. |
182 m1.UnpoisonValue(); | |
144 new (&m1.value_) T(std::move(m2.value_)); | 183 new (&m1.value_) T(std::move(m2.value_)); |
145 m2.value_.~T(); // Destroy the moved-from value. | 184 m2.value_.~T(); // Destroy the moved-from value. |
146 m1.has_value_ = true; | 185 m1.has_value_ = true; |
147 m2.has_value_ = false; | 186 m2.has_value_ = false; |
187 m2.PoisonValue(); | |
148 } | 188 } |
149 } | 189 } |
150 | 190 |
151 // Conversion to bool to test if we have a value. | 191 // Conversion to bool to test if we have a value. |
152 explicit operator bool() const { return has_value_; } | 192 explicit operator bool() const { return has_value_; } |
153 | 193 |
154 // Dereferencing. Only allowed if we have a value. | 194 // Dereferencing. Only allowed if we have a value. |
155 const T* operator->() const { | 195 const T* operator->() const { |
156 RTC_DCHECK(has_value_); | 196 RTC_DCHECK(has_value_); |
157 return &value_; | 197 return &value_; |
158 } | 198 } |
159 T* operator->() { | 199 T* operator->() { |
160 RTC_DCHECK(has_value_); | 200 RTC_DCHECK(has_value_); |
161 return &value_; | 201 return &value_; |
162 } | 202 } |
163 const T& operator*() const { | 203 const T& operator*() const { |
164 RTC_DCHECK(has_value_); | 204 RTC_DCHECK(has_value_); |
165 return value_; | 205 return value_; |
166 } | 206 } |
167 T& operator*() { | 207 T& operator*() { |
168 RTC_DCHECK(has_value_); | 208 RTC_DCHECK(has_value_); |
169 return value_; | 209 return value_; |
170 } | 210 } |
171 | 211 |
172 // Dereference with a default value in case we don't have a value. | 212 // Dereference with a default value in case we don't have a value. |
173 const T& value_or(const T& default_val) const { | 213 const T& value_or(const T& default_val) const { |
174 return has_value_ ? value_ : default_val; | 214 if (has_value_) { |
215 // This no-op call prevents the optimizer from going this way and reading | |
216 // value_ if !has_value_ (but only if FunctionThatDoesNothing is not | |
217 // completely inlined; see its declaration.). | |
218 return *internal::FunctionThatDoesNothing(&value_); | |
219 } else { | |
tommi
2016/09/03 15:00:50
nit: else not necessary
kwiberg-webrtc
2016/09/03 16:05:36
Done.
| |
220 return default_val; | |
221 } | |
175 } | 222 } |
176 | 223 |
177 // Equality tests. Two Optionals are equal if they contain equivalent values, | 224 // Equality tests. Two Optionals are equal if they contain equivalent values, |
178 // or | 225 // or |
179 // if they're both empty. | 226 // if they're both empty. |
180 friend bool operator==(const Optional& m1, const Optional& m2) { | 227 friend bool operator==(const Optional& m1, const Optional& m2) { |
181 return m1.has_value_ && m2.has_value_ ? m1.value_ == m2.value_ | 228 return m1.has_value_ && m2.has_value_ ? m1.value_ == m2.value_ |
182 : m1.has_value_ == m2.has_value_; | 229 : m1.has_value_ == m2.has_value_; |
183 } | 230 } |
184 friend bool operator!=(const Optional& m1, const Optional& m2) { | 231 friend bool operator!=(const Optional& m1, const Optional& m2) { |
185 return m1.has_value_ && m2.has_value_ ? m1.value_ != m2.value_ | 232 return m1.has_value_ && m2.has_value_ ? m1.value_ != m2.value_ |
186 : m1.has_value_ != m2.has_value_; | 233 : m1.has_value_ != m2.has_value_; |
187 } | 234 } |
188 | 235 |
189 private: | 236 private: |
237 // Tell sanitizers that value_ shouldn't be touched. | |
238 void PoisonValue() { | |
239 rtc::AsanPoison(rtc::MakeArrayView(&value_, 1)); | |
240 rtc::MsanMarkUninitialized(rtc::MakeArrayView(&value_, 1)); | |
241 } | |
242 | |
243 // Tell sanitizers that value_ is OK to touch again. | |
244 void UnpoisonValue() { | |
245 rtc::AsanUnpoison(rtc::MakeArrayView(&value_, 1)); | |
246 } | |
247 | |
190 bool has_value_; // True iff value_ contains a live value. | 248 bool has_value_; // True iff value_ contains a live value. |
191 union { | 249 union { |
192 // empty_ exists only to make it possible to initialize the union, even when | 250 // empty_ exists only to make it possible to initialize the union, even when |
193 // it doesn't contain any data. If the union goes uninitialized, it may | 251 // it doesn't contain any data. If the union goes uninitialized, it may |
194 // trigger compiler warnings. | 252 // trigger compiler warnings. |
195 char empty_; | 253 char empty_; |
196 // By placing value_ in a union, we get to manage its construction and | 254 // By placing value_ in a union, we get to manage its construction and |
197 // destruction manually: the Optional constructors won't automatically | 255 // destruction manually: the Optional constructors won't automatically |
198 // construct it, and the Optional destructor won't automatically destroy | 256 // construct it, and the Optional destructor won't automatically destroy |
199 // it. Basically, this just allocates a properly sized and aligned block of | 257 // it. Basically, this just allocates a properly sized and aligned block of |
200 // memory in which we can manually put a T with placement new. | 258 // memory in which we can manually put a T with placement new. |
201 T value_; | 259 T value_; |
202 }; | 260 }; |
203 }; | 261 }; |
204 | 262 |
205 } // namespace rtc | 263 } // namespace rtc |
206 | 264 |
207 #endif // WEBRTC_BASE_OPTIONAL_H_ | 265 #endif // WEBRTC_BASE_OPTIONAL_H_ |
OLD | NEW |