scoped_typeref.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_MAC_SCOPED_TYPEREF_H_
  5. #define BASE_MAC_SCOPED_TYPEREF_H_
  6. #include "base/check.h"
  7. #include "base/memory/scoped_policy.h"
  8. namespace base {
  9. // ScopedTypeRef<> is patterned after std::unique_ptr<>, but maintains ownership
  10. // of a reference to any type that is maintained by Retain and Release methods.
  11. //
  12. // The Traits structure must provide the Retain and Release methods for type T.
  13. // A default ScopedTypeRefTraits is used but not defined, and should be defined
  14. // for each type to use this interface. For example, an appropriate definition
  15. // of ScopedTypeRefTraits for CGLContextObj would be:
  16. //
  17. // template<>
  18. // struct ScopedTypeRefTraits<CGLContextObj> {
  19. // static CGLContextObj InvalidValue() { return nullptr; }
  20. // static CGLContextObj Retain(CGLContextObj object) {
  21. // CGLContextRetain(object);
  22. // return object;
  23. // }
  24. // static void Release(CGLContextObj object) { CGLContextRelease(object); }
  25. // };
  26. //
  27. // For the many types that have pass-by-pointer create functions, the function
  28. // InitializeInto() is provided to allow direct initialization and assumption
  29. // of ownership of the object. For example, continuing to use the above
  30. // CGLContextObj specialization:
  31. //
  32. // base::ScopedTypeRef<CGLContextObj> context;
  33. // CGLCreateContext(pixel_format, share_group, context.InitializeInto());
  34. //
  35. // For initialization with an existing object, the caller may specify whether
  36. // the ScopedTypeRef<> being initialized is assuming the caller's existing
  37. // ownership of the object (and should not call Retain in initialization) or if
  38. // it should not assume this ownership and must create its own (by calling
  39. // Retain in initialization). This behavior is based on the |policy| parameter,
  40. // with |ASSUME| for the former and |RETAIN| for the latter. The default policy
  41. // is to |ASSUME|.
  42. template<typename T>
  43. struct ScopedTypeRefTraits;
  44. template<typename T, typename Traits = ScopedTypeRefTraits<T>>
  45. class ScopedTypeRef {
  46. public:
  47. using element_type = T;
  48. explicit constexpr ScopedTypeRef(
  49. element_type object = Traits::InvalidValue(),
  50. base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
  51. : object_(object) {
  52. if (object_ && policy == base::scoped_policy::RETAIN)
  53. object_ = Traits::Retain(object_);
  54. }
  55. ScopedTypeRef(const ScopedTypeRef<T, Traits>& that)
  56. : object_(that.object_) {
  57. if (object_)
  58. object_ = Traits::Retain(object_);
  59. }
  60. // This allows passing an object to a function that takes its superclass.
  61. template <typename R, typename RTraits>
  62. explicit ScopedTypeRef(const ScopedTypeRef<R, RTraits>& that_as_subclass)
  63. : object_(that_as_subclass.get()) {
  64. if (object_)
  65. object_ = Traits::Retain(object_);
  66. }
  67. ScopedTypeRef(ScopedTypeRef<T, Traits>&& that) : object_(that.object_) {
  68. that.object_ = Traits::InvalidValue();
  69. }
  70. ~ScopedTypeRef() {
  71. if (object_)
  72. Traits::Release(object_);
  73. }
  74. ScopedTypeRef& operator=(const ScopedTypeRef<T, Traits>& that) {
  75. reset(that.get(), base::scoped_policy::RETAIN);
  76. return *this;
  77. }
  78. // This is to be used only to take ownership of objects that are created
  79. // by pass-by-pointer create functions. To enforce this, require that the
  80. // object be reset to NULL before this may be used.
  81. [[nodiscard]] element_type* InitializeInto() {
  82. DCHECK(!object_);
  83. return &object_;
  84. }
  85. void reset(const ScopedTypeRef<T, Traits>& that) {
  86. reset(that.get(), base::scoped_policy::RETAIN);
  87. }
  88. void reset(element_type object = Traits::InvalidValue(),
  89. base::scoped_policy::OwnershipPolicy policy =
  90. base::scoped_policy::ASSUME) {
  91. if (object && policy == base::scoped_policy::RETAIN)
  92. object = Traits::Retain(object);
  93. if (object_)
  94. Traits::Release(object_);
  95. object_ = object;
  96. }
  97. bool operator==(const ScopedTypeRef& that) const {
  98. return object_ == that.object_;
  99. }
  100. bool operator!=(const ScopedTypeRef& that) const {
  101. return object_ != that.object_;
  102. }
  103. operator element_type() const { return object_; }
  104. element_type get() const { return object_; }
  105. void swap(ScopedTypeRef& that) {
  106. element_type temp = that.object_;
  107. that.object_ = object_;
  108. object_ = temp;
  109. }
  110. // ScopedTypeRef<>::release() is like std::unique_ptr<>::release. It is NOT
  111. // a wrapper for Release(). To force a ScopedTypeRef<> object to call
  112. // Release(), use ScopedTypeRef<>::reset().
  113. [[nodiscard]] element_type release() {
  114. element_type temp = object_;
  115. object_ = Traits::InvalidValue();
  116. return temp;
  117. }
  118. private:
  119. element_type object_;
  120. };
  121. } // namespace base
  122. #endif // BASE_MAC_SCOPED_TYPEREF_H_