1 //===-- CFCReleaser.h -------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef CoreFoundationCPP_CFReleaser_h_
11 #define CoreFoundationCPP_CFReleaser_h_
12 
13 #include <CoreFoundation/CoreFoundation.h>
14 
15 #ifdef __cplusplus
16 
17 #include <assert.h>
18 
19 //----------------------------------------------------------------------
20 // Templatized CF helper class that can own any CF pointer and will
21 // call CFRelease() on any valid pointer it owns unless that pointer is
22 // explicitly released using the release() member function. This class
23 // is designed to mimic the std::auto_ptr<T> class and has all of the
24 // same functions. The one thing to watch out for is the
25 // CFCReleaser<T>::release() function won't actually CFRelease any owned
26 // pointer, it is designed to relinquish ownership of the pointer just
27 // like std:auto_ptr<T>::release() does.
28 //----------------------------------------------------------------------
29 template <class T> class CFCReleaser {
30 public:
31   //----------------------------------------------------------
32   // Constructor that takes a pointer to a CF object that is
33   // to be released when this object goes out of scope
34   //----------------------------------------------------------
35   CFCReleaser(T ptr = NULL) : _ptr(ptr) {}
36 
37   //----------------------------------------------------------
38   // Copy constructor
39   //
40   // Note that copying a CFCReleaser will not transfer
41   // ownership of the contained pointer, but it will bump its
42   // reference count. This is where this class differs from
43   // std::auto_ptr.
44   //----------------------------------------------------------
45   CFCReleaser(const CFCReleaser &rhs) : _ptr(rhs.get()) {
46     if (get())
47       ::CFRetain(get());
48   }
49 
50   //----------------------------------------------------------
51   // The destructor will release the pointer that it contains
52   // if it has a valid pointer.
53   //----------------------------------------------------------
54   virtual ~CFCReleaser() { reset(); }
55 
56   //----------------------------------------------------------
57   // Assignment operator.
58   //
59   // Note that assigning one CFCReleaser to another will
60   // not transfer ownership of the contained pointer, but it
61   // will bump its reference count. This is where this class
62   // differs from std::auto_ptr.
63   //----------------------------------------------------------
64   CFCReleaser &operator=(const CFCReleaser<T> &rhs) {
65     if (this != &rhs) {
66       // Replace our owned pointer with the new one
67       reset(rhs.get());
68       // Retain the current pointer that we own
69       if (get())
70         ::CFRetain(get());
71     }
72     return *this;
73   }
74 
75   //----------------------------------------------------------
76   // Get the address of the contained type in case it needs
77   // to be passed to a function that will fill in a pointer
78   // value. The function currently will assert if _ptr is not
79   // NULL because the only time this method should be used is
80   // if another function will modify the contents, and we
81   // could leak a pointer if this is not NULL. If the
82   // assertion fires, check the offending code, or call
83   // reset() prior to using the "ptr_address()" member to make
84   // sure any owned objects has CFRelease called on it.
85   // I had to add the "enforce_null" bool here because some
86   // API's require the pointer address even though they don't change it.
87   //----------------------------------------------------------
88   T *ptr_address(bool enforce_null = true) {
89     if (enforce_null)
90       assert(_ptr == NULL);
91     return &_ptr;
92   }
93 
94   //----------------------------------------------------------
95   // Access the pointer itself
96   //----------------------------------------------------------
97   T get() { return _ptr; }
98 
99   const T get() const { return _ptr; }
100 
101   //----------------------------------------------------------
102   // Set a new value for the pointer and CFRelease our old
103   // value if we had a valid one.
104   //----------------------------------------------------------
105   void reset(T ptr = NULL) {
106     if ((_ptr != NULL) && (ptr != _ptr))
107       ::CFRelease(_ptr);
108     _ptr = ptr;
109   }
110 
111   //----------------------------------------------------------
112   // Release ownership without calling CFRelease. This class
113   // is designed to mimic std::auto_ptr<T>, so the release
114   // method releases ownership of the contained pointer
115   // and does NOT call CFRelease.
116   //----------------------------------------------------------
117   T release() {
118     T tmp = _ptr;
119     _ptr = NULL;
120     return tmp;
121   }
122 
123 private:
124   T _ptr;
125 };
126 
127 #endif // #ifdef __cplusplus
128 #endif // #ifndef CoreFoundationCPP_CFReleaser_h_
129