File: scoped_typeref.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (189 lines) | stat: -rw-r--r-- 6,309 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_APPLE_SCOPED_TYPEREF_H_
#define BASE_APPLE_SCOPED_TYPEREF_H_

#include "base/check_op.h"
#include "base/memory/scoped_policy.h"

namespace base::apple {

// ScopedTypeRef<> is patterned after std::shared_ptr<>, but maintains ownership
// of a reference to any type that is maintained by Retain and Release methods.
//
// The Traits structure must provide the Retain and Release methods for type T.
// A default ScopedTypeRefTraits is used but not defined, and should be defined
// for each type to use this interface. For example, an appropriate definition
// of ScopedTypeRefTraits for CGLContextObj would be:
//
//   template<>
//   struct ScopedTypeRefTraits<CGLContextObj> {
//     static CGLContextObj InvalidValue() { return nullptr; }
//     static CGLContextObj Retain(CGLContextObj object) {
//       CGLContextRetain(object);
//       return object;
//     }
//     static void Release(CGLContextObj object) { CGLContextRelease(object); }
//   };
//
// For the many types that have pass-by-pointer create functions, the function
// InitializeInto() is provided to allow direct initialization and assumption
// of ownership of the object. For example, continuing to use the above
// CGLContextObj specialization:
//
//   base::apple::ScopedTypeRef<CGLContextObj> context;
//   CGLCreateContext(pixel_format, share_group, context.InitializeInto());
//
// For initialization with an existing object, the caller may specify whether
// the ScopedTypeRef<> being initialized is assuming the caller's existing
// ownership of the object (and should not call Retain in initialization) or if
// it should not assume this ownership and must create its own (by calling
// Retain in initialization). This behavior is based on the `policy` parameter,
// with `ASSUME` for the former and `RETAIN` for the latter. The default policy
// is to `ASSUME`.

template <typename T>
struct ScopedTypeRefTraits;

template <typename T, typename Traits = ScopedTypeRefTraits<T>>
class ScopedTypeRef {
 public:
  using element_type = T;

  // Construction from underlying type

  explicit constexpr ScopedTypeRef(
      element_type object = Traits::InvalidValue(),
      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
      : object_(object) {
    if (object_ != Traits::InvalidValue() &&
        policy == base::scoped_policy::RETAIN) {
      object_ = Traits::Retain(object_);
    }
  }

  // The pattern in the four [copy|move] [constructors|assignment operators]
  // below is that for each of them there is the standard version for use by
  // scopers wrapping objects of this type, and a templated version to handle
  // scopers wrapping objects of subtypes. One might think that one could get
  // away only the templated versions, as their templates should match the
  // usage, but that doesn't work. Having a templated function that matches the
  // types of, say, a copy constructor, doesn't count as a copy constructor, and
  // the compiler's generated copy constructor is incorrect.

  // Copy construction

  ScopedTypeRef(const ScopedTypeRef<T, Traits>& that) : object_(that.get()) {
    if (object_ != Traits::InvalidValue()) {
      object_ = Traits::Retain(object_);
    }
  }

  template <typename R, typename RTraits>
  ScopedTypeRef(const ScopedTypeRef<R, RTraits>& that) : object_(that.get()) {
    if (object_ != Traits::InvalidValue()) {
      object_ = Traits::Retain(object_);
    }
  }

  // Copy assignment

  ScopedTypeRef& operator=(const ScopedTypeRef<T, Traits>& that) {
    reset(that.get(), base::scoped_policy::RETAIN);
    return *this;
  }

  template <typename R, typename RTraits>
  ScopedTypeRef& operator=(const ScopedTypeRef<R, RTraits>& that) {
    reset(that.get(), base::scoped_policy::RETAIN);
    return *this;
  }

  // Move construction

  ScopedTypeRef(ScopedTypeRef<T, Traits>&& that) : object_(that.release()) {}

  template <typename R, typename RTraits>
  ScopedTypeRef(ScopedTypeRef<R, RTraits>&& that) : object_(that.release()) {}

  // Move assignment

  ScopedTypeRef& operator=(ScopedTypeRef<T, Traits>&& that) {
    reset(that.release(), base::scoped_policy::ASSUME);
    return *this;
  }

  template <typename R, typename RTraits>
  ScopedTypeRef& operator=(ScopedTypeRef<R, RTraits>&& that) {
    reset(that.release(), base::scoped_policy::ASSUME);
    return *this;
  }

  // Resetting

  template <typename R, typename RTraits>
  void reset(const ScopedTypeRef<R, RTraits>& that) {
    reset(that.get(), base::scoped_policy::RETAIN);
  }

  void reset(element_type object = Traits::InvalidValue(),
             base::scoped_policy::OwnershipPolicy policy =
                 base::scoped_policy::ASSUME) {
    if (object != Traits::InvalidValue() &&
        policy == base::scoped_policy::RETAIN) {
      object = Traits::Retain(object);
    }
    if (object_ != Traits::InvalidValue()) {
      Traits::Release(object_);
    }
    object_ = object;
  }

  // Destruction

  ~ScopedTypeRef() {
    if (object_ != Traits::InvalidValue()) {
      Traits::Release(object_);
    }
  }

  // This is to be used only to take ownership of objects that are created by
  // pass-by-pointer create functions. To enforce this, require that this object
  // be empty before use.
  [[nodiscard]] element_type* InitializeInto() {
    CHECK_EQ(object_, Traits::InvalidValue());
    return &object_;
  }

  bool operator==(const ScopedTypeRef& that) const {
    return object_ == that.object_;
  }

  explicit operator bool() const { return object_ != Traits::InvalidValue(); }

  element_type get() const { return object_; }

  void swap(ScopedTypeRef& that) {
    element_type temp = that.object_;
    that.object_ = object_;
    object_ = temp;
  }

  // ScopedTypeRef<>::release() is like std::unique_ptr<>::release.  It is NOT
  // a wrapper for Release().  To force a ScopedTypeRef<> object to call
  // Release(), use ScopedTypeRef<>::reset().
  [[nodiscard]] element_type release() {
    element_type temp = object_;
    object_ = Traits::InvalidValue();
    return temp;
  }

 private:
  element_type object_;
};

}  // namespace base::apple

#endif  // BASE_APPLE_SCOPED_TYPEREF_H_