OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef BASE_MEMORY_REF_COUNTED_H_ | 5 #ifndef BASE_MEMORY_REF_COUNTED_H_ |
6 #define BASE_MEMORY_REF_COUNTED_H_ | 6 #define BASE_MEMORY_REF_COUNTED_H_ |
7 | 7 |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 | 9 |
10 #include <cassert> | 10 #include <cassert> |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 // // now, |a| and |b| each own a reference to the same MyFoo object. | 264 // // now, |a| and |b| each own a reference to the same MyFoo object. |
265 // } | 265 // } |
266 // | 266 // |
267 template <class T> | 267 template <class T> |
268 class scoped_refptr { | 268 class scoped_refptr { |
269 public: | 269 public: |
270 typedef T element_type; | 270 typedef T element_type; |
271 | 271 |
272 scoped_refptr() {} | 272 scoped_refptr() {} |
273 | 273 |
274 scoped_refptr(T* p) : ptr_(p) { | 274 scoped_refptr(T* p) : ptr_(p), ptr_caller_(&PtrCallerImpl) { |
275 if (ptr_) | 275 if (ptr_) |
276 AddRef(ptr_); | 276 ptr_caller_(ptr_, PtrCall::AddRef); |
277 } | 277 } |
278 | 278 |
279 // Copy constructor. | 279 // Copy constructor. |
280 scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) { | 280 scoped_refptr(const scoped_refptr<T>& r) |
| 281 : ptr_(r.ptr_), ptr_caller_(r.ptr_caller_) { |
281 if (ptr_) | 282 if (ptr_) |
282 AddRef(ptr_); | 283 ptr_caller_(ptr_, PtrCall::AddRef); |
283 } | 284 } |
284 | 285 |
285 // Copy conversion constructor. | 286 // Copy conversion constructor. |
286 template <typename U, | 287 template <typename U, |
287 typename = typename std::enable_if< | 288 typename = typename std::enable_if< |
288 std::is_convertible<U*, T*>::value>::type> | 289 std::is_convertible<U*, T*>::value>::type> |
289 scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) { | 290 scoped_refptr(const scoped_refptr<U>& r) |
| 291 : ptr_(r.get()), ptr_caller_(&PtrCallerImpl) { |
290 if (ptr_) | 292 if (ptr_) |
291 AddRef(ptr_); | 293 ptr_caller_(ptr_, PtrCall::AddRef); |
292 } | 294 } |
293 | 295 |
294 // Move constructor. This is required in addition to the conversion | 296 // Move constructor. This is required in addition to the conversion |
295 // constructor below in order for clang to warn about pessimizing moves. | 297 // constructor below in order for clang to warn about pessimizing moves. |
296 scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; } | 298 scoped_refptr(scoped_refptr&& r) : ptr_(r.get()), ptr_caller_(r.ptr_caller_) { |
| 299 r.ptr_ = nullptr; |
| 300 } |
297 | 301 |
298 // Move conversion constructor. | 302 // Move conversion constructor. |
299 template <typename U, | 303 template <typename U, |
300 typename = typename std::enable_if< | 304 typename = typename std::enable_if< |
301 std::is_convertible<U*, T*>::value>::type> | 305 std::is_convertible<U*, T*>::value>::type> |
302 scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) { | 306 scoped_refptr(scoped_refptr<U>&& r) |
| 307 : ptr_(r.get()), ptr_caller_(&PtrCallerImpl) { |
303 r.ptr_ = nullptr; | 308 r.ptr_ = nullptr; |
304 } | 309 } |
305 | 310 |
306 ~scoped_refptr() { | 311 ~scoped_refptr() { |
307 if (ptr_) | 312 if (ptr_) |
308 Release(ptr_); | 313 ptr_caller_(ptr_, PtrCall::Release); |
309 } | 314 } |
310 | 315 |
311 T* get() const { return ptr_; } | 316 T* get() const { return ptr_; } |
312 | 317 |
313 T& operator*() const { | 318 T& operator*() const { |
314 assert(ptr_ != nullptr); | 319 assert(ptr_ != nullptr); |
315 return *ptr_; | 320 return *ptr_; |
316 } | 321 } |
317 | 322 |
318 T* operator->() const { | 323 T* operator->() const { |
319 assert(ptr_ != nullptr); | 324 assert(ptr_ != nullptr); |
320 return ptr_; | 325 return ptr_; |
321 } | 326 } |
322 | 327 |
323 scoped_refptr<T>& operator=(T* p) { | 328 scoped_refptr<T>& operator=(T* p) { |
324 // AddRef first so that self assignment should work | 329 Assign(p, &PtrCallerImpl); |
325 if (p) | |
326 AddRef(p); | |
327 T* old_ptr = ptr_; | |
328 ptr_ = p; | |
329 if (old_ptr) | |
330 Release(old_ptr); | |
331 return *this; | 330 return *this; |
332 } | 331 } |
333 | 332 |
334 scoped_refptr<T>& operator=(const scoped_refptr<T>& r) { | 333 scoped_refptr<T>& operator=(const scoped_refptr<T>& r) { |
335 return *this = r.ptr_; | 334 Assign(r.ptr_, r.ptr_caller_); |
| 335 return *this; |
336 } | 336 } |
337 | 337 |
338 template <typename U> | 338 template <typename U> |
339 scoped_refptr<T>& operator=(const scoped_refptr<U>& r) { | 339 scoped_refptr<T>& operator=(const scoped_refptr<U>& r) { |
340 return *this = r.get(); | 340 Assign(r.get(), &PtrCallerImpl); |
| 341 return *this; |
341 } | 342 } |
342 | 343 |
343 scoped_refptr<T>& operator=(scoped_refptr<T>&& r) { | 344 scoped_refptr<T>& operator=(scoped_refptr<T>&& r) { |
344 scoped_refptr<T>(std::move(r)).swap(*this); | 345 scoped_refptr<T>(std::move(r)).swap(*this); |
345 return *this; | 346 return *this; |
346 } | 347 } |
347 | 348 |
348 template <typename U> | 349 template <typename U> |
349 scoped_refptr<T>& operator=(scoped_refptr<U>&& r) { | 350 scoped_refptr<T>& operator=(scoped_refptr<U>&& r) { |
350 scoped_refptr<T>(std::move(r)).swap(*this); | 351 scoped_refptr<T>(std::move(r)).swap(*this); |
351 return *this; | 352 return *this; |
352 } | 353 } |
353 | 354 |
354 void swap(T** pp) { | 355 void swap(T** pp) { |
355 T* p = ptr_; | 356 T* p = ptr_; |
356 ptr_ = *pp; | 357 ptr_ = *pp; |
| 358 ptr_caller_ = &PtrCallerImpl; |
357 *pp = p; | 359 *pp = p; |
358 } | 360 } |
359 | 361 |
360 void swap(scoped_refptr<T>& r) { | 362 void swap(scoped_refptr<T>& r) { |
361 swap(&r.ptr_); | 363 std::swap(ptr_, r.ptr_); |
| 364 std::swap(ptr_caller_, r.ptr_caller_); |
362 } | 365 } |
363 | 366 |
364 explicit operator bool() const { return ptr_ != nullptr; } | 367 explicit operator bool() const { return ptr_ != nullptr; } |
365 | 368 |
366 template <typename U> | 369 template <typename U> |
367 bool operator==(const scoped_refptr<U>& rhs) const { | 370 bool operator==(const scoped_refptr<U>& rhs) const { |
368 return ptr_ == rhs.get(); | 371 return ptr_ == rhs.get(); |
369 } | 372 } |
370 | 373 |
371 template <typename U> | 374 template <typename U> |
372 bool operator!=(const scoped_refptr<U>& rhs) const { | 375 bool operator!=(const scoped_refptr<U>& rhs) const { |
373 return !operator==(rhs); | 376 return !operator==(rhs); |
374 } | 377 } |
375 | 378 |
376 template <typename U> | 379 template <typename U> |
377 bool operator<(const scoped_refptr<U>& rhs) const { | 380 bool operator<(const scoped_refptr<U>& rhs) const { |
378 return ptr_ < rhs.get(); | 381 return ptr_ < rhs.get(); |
379 } | 382 } |
380 | 383 |
381 protected: | 384 protected: |
| 385 enum class PtrCall { AddRef, Release }; |
| 386 using PtrCallerFunction = void (*)(T* ptr, PtrCall call); |
| 387 |
| 388 static void PtrCallerImpl(T* ptr, PtrCall call) { |
| 389 switch (call) { |
| 390 case PtrCall::AddRef: |
| 391 ptr->AddRef(); |
| 392 break; |
| 393 case PtrCall::Release: |
| 394 ptr->Release(); |
| 395 break; |
| 396 } |
| 397 } |
| 398 |
382 T* ptr_ = nullptr; | 399 T* ptr_ = nullptr; |
| 400 PtrCallerFunction ptr_caller_ = nullptr; |
383 | 401 |
384 private: | 402 private: |
385 // Friend required for move constructors that set r.ptr_ to null. | |
386 template <typename U> | 403 template <typename U> |
387 friend class scoped_refptr; | 404 friend class scoped_refptr; |
388 | 405 |
389 // Non-inline helpers to allow: | 406 void Assign(T* p, PtrCallerFunction caller) { |
390 // class Opaque; | 407 // AddRef first so that self assignment should work |
391 // extern template class scoped_refptr<Opaque>; | 408 if (p) |
392 // Otherwise the compiler will complain that Opaque is an incomplete type. | 409 caller(p, PtrCall::AddRef); |
393 static void AddRef(T* ptr); | 410 T* old_ptr = ptr_; |
394 static void Release(T* ptr); | 411 PtrCallerFunction old_caller = ptr_caller_; |
| 412 ptr_ = p; |
| 413 ptr_caller_ = caller; |
| 414 if (old_ptr) |
| 415 old_caller(old_ptr, PtrCall::Release); |
| 416 // Release above can potentially delete this object |
| 417 } |
395 }; | 418 }; |
396 | 419 |
397 // static | |
398 template <typename T> | |
399 void scoped_refptr<T>::AddRef(T* ptr) { | |
400 ptr->AddRef(); | |
401 } | |
402 | |
403 // static | |
404 template <typename T> | |
405 void scoped_refptr<T>::Release(T* ptr) { | |
406 ptr->Release(); | |
407 } | |
408 | |
409 // Handy utility for creating a scoped_refptr<T> out of a T* explicitly without | 420 // Handy utility for creating a scoped_refptr<T> out of a T* explicitly without |
410 // having to retype all the template arguments | 421 // having to retype all the template arguments |
411 template <typename T> | 422 template <typename T> |
412 scoped_refptr<T> make_scoped_refptr(T* t) { | 423 scoped_refptr<T> make_scoped_refptr(T* t) { |
413 return scoped_refptr<T>(t); | 424 return scoped_refptr<T>(t); |
414 } | 425 } |
415 | 426 |
416 template <typename T, typename U> | 427 template <typename T, typename U> |
417 bool operator==(const scoped_refptr<T>& lhs, const U* rhs) { | 428 bool operator==(const scoped_refptr<T>& lhs, const U* rhs) { |
418 return lhs.get() == rhs; | 429 return lhs.get() == rhs; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
452 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { | 463 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { |
453 return !operator==(null, rhs); | 464 return !operator==(null, rhs); |
454 } | 465 } |
455 | 466 |
456 template <typename T> | 467 template <typename T> |
457 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { | 468 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { |
458 return out << p.get(); | 469 return out << p.get(); |
459 } | 470 } |
460 | 471 |
461 #endif // BASE_MEMORY_REF_COUNTED_H_ | 472 #endif // BASE_MEMORY_REF_COUNTED_H_ |
OLD | NEW |