OLD | NEW |
---|---|
(Empty) | |
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 | |
5 #ifndef BASE_SCOPED_GENERIC_H_ | |
6 #define BASE_SCOPED_GENERIC_H_ | |
7 | |
8 #include <stdlib.h> | |
9 | |
10 #include "base/compiler_specific.h" | |
11 #include "base/move.h" | |
12 | |
13 namespace base { | |
14 | |
15 // This class acts like ScopedPtr with a custom deleter (although is slightly | |
16 // less fancy in some of the more escoteric respects) except that it keeps a | |
17 // copy of the object rather than a pointer, and we require that the contained | |
18 // object has some kind of "null" value. | |
awong
2014/03/11 23:40:49
null -> invalid
| |
19 // | |
20 // Defining a scoper based on this class allows you to get a scoper for | |
21 // non-pointer types without having to write custom code for set, reset, and | |
22 // move, etc. and get almost identical semantics that people are used to from | |
23 // scoped_ptr. | |
24 // | |
25 // It is intended that you will typedef this class with an appropriate deleter | |
26 // to implement clean up tasks for objects that act like pointers from a | |
27 // resource management standpoint but aren't, such as file descriptors and | |
28 // various types of operating system handles. Using scoped_ptr for these | |
29 // things requires that you keep a pointer to the handle valid for the lifetime | |
30 // of the scoper (which is easy to mess up). | |
31 // | |
32 // For an object to be able to be put into a ScopedGeneric, it must support | |
33 // standard copyable semantics and have a specific "invalid" value. The traits | |
34 // must define a free function and also the invalid value to assign for | |
35 // default-constructed and released objects. | |
36 // | |
37 // struct FooScopedTraits { | |
38 // // It's assumed that this is a fast inline function with little-to-no | |
39 // // penalty for duplicate calls. This must be a static function even | |
40 // // for stateful traits. | |
41 // static int InvalidValue() { | |
42 // return 0; | |
43 // } | |
44 // | |
45 // // This free function will not be called if f == InvalidValue()! | |
46 // static void Free(int f) { | |
47 // ::FreeFoo(f); | |
48 // } | |
49 // }; | |
50 // | |
51 // typedef ScopedGeneric<int, FooScopedTraits> ScopedFoo; | |
52 template<typename T, typename Traits> | |
53 class ScopedGeneric { | |
54 MOVE_ONLY_TYPE_FOR_CPP_03(ScopedGeneric, RValue) | |
55 | |
56 private: | |
57 // This must be first since it's used inline below. | |
58 // | |
59 // Use the empty base class optimization to allow us to have a D | |
60 // member, while avoiding any space overhead for it when D is an | |
61 // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good | |
62 // discussion of this technique. | |
63 struct Data : public Traits { | |
64 explicit Data(const T& in) : generic(in) {} | |
65 Data(const T& in, const Traits& other) : Traits(other), generic(in) {} | |
66 T generic; | |
67 }; | |
68 | |
69 public: | |
70 typedef T element_type; | |
71 typedef Traits traits_type; | |
72 | |
73 ScopedGeneric() : data_(traits_type::InvalidValue()) {} | |
74 | |
75 // Constructor. Takes responsibility for freeing the resource associated with | |
76 // the object T. | |
77 explicit ScopedGeneric(const element_type& value) : data_(value) {} | |
78 | |
79 // Constructor. Allows initialization of a stateful traits object. | |
80 ScopedGeneric(const element_type& value, const traits_type& traits) | |
81 : data_(value, traits) { | |
82 } | |
83 | |
84 // Move constructor for C++03 move emulation. | |
85 ScopedGeneric(RValue rvalue) | |
86 : data_(rvalue.object->release(), rvalue.object->get_traits()) { | |
87 } | |
88 | |
89 ~ScopedGeneric() { | |
90 FreeIfNecessary(); | |
91 } | |
92 | |
93 ScopedGeneric& operator=(ScopedGeneric rhs) { | |
94 reset(rhs.release()); | |
95 get_traits() = rhs.get_traits(); | |
96 } | |
97 | |
98 // Frees the currently owned object, if any. Then takes ownership of a new | |
99 // object, if given. Self-resets are not allowd as on scoped_ptr. See | |
100 // http://crbug.com/162971 | |
101 void reset(const element_type& value = traits_type::InvalidValue()) { | |
102 if (data_.generic != traits_type::InvalidValue() && data_.generic == value) | |
103 abort(); | |
104 FreeIfNecessary(); | |
105 data_.generic = value; | |
106 } | |
107 | |
108 void swap(ScopedGeneric& other) { | |
109 // Standard swap idiom: 'using std::swap' ensures that std::swap is | |
110 // present in the overload set, but we call swap unqualified so that | |
111 // any more-specific overloads can be used, if available. | |
112 using std::swap; | |
113 swap(static_cast<Traits&>(data_), static_cast<Traits&>(other.data_)); | |
114 swap(data_.generic, other.data_.generic); | |
115 } | |
116 | |
117 // Release the object. The return value is the current object held by this | |
118 // object. After this operation, this object will hold a null value, and | |
119 // will not own the object any more. | |
120 element_type release() WARN_UNUSED_RESULT { | |
121 element_type old_generic = data_.generic; | |
122 data_.generic = traits_type::InvalidValue(); | |
123 return old_generic; | |
124 } | |
125 | |
126 const element_type& get() const { return data_.generic; } | |
127 | |
128 // Returns true if this object doesn't hold the special null value for the | |
129 // associated data type. | |
130 bool is_valid() const { return data_.generic != traits_type::InvalidValue(); } | |
131 | |
132 bool operator==(const element_type& value) const { | |
133 return data_.generic == value; | |
134 } | |
135 bool operator!=(const element_type& value) const { | |
136 return data_.generic != value; | |
137 } | |
138 | |
139 Traits& get_traits() { return data_; } | |
140 const Traits& get_traits() const { return data_; } | |
141 | |
142 private: | |
143 void FreeIfNecessary() { | |
144 if (data_.generic != traits_type::InvalidValue()) { | |
145 data_.Free(data_.generic); | |
146 data_.generic = traits_type::InvalidValue(); | |
147 } | |
148 } | |
149 | |
150 // Forbid comparison. If U != T, it totally doesn't make sense, and if U == | |
151 // T, it still doesn't make sense because you should never have the same | |
152 // object owned by two different ScopedGenerics. | |
153 template <typename T2, typename Traits2> bool operator==( | |
154 const ScopedGeneric<T2, Traits2>& p2) const; | |
155 template <typename T2, typename Traits2> bool operator!=( | |
156 const ScopedGeneric<T2, Traits2>& p2) const; | |
157 | |
158 Data data_; | |
159 }; | |
160 | |
161 template<class T, class Traits> | |
162 void swap(const ScopedGeneric<T, Traits>& a, | |
163 const ScopedGeneric<T, Traits>& b) { | |
164 a.swap(b); | |
165 } | |
166 | |
167 template<class T, class Traits> | |
168 bool operator==(const T& value, const ScopedGeneric<T, Traits>& scoped) { | |
169 return value == scoped.get(); | |
170 } | |
171 | |
172 template<class T, class Traits> | |
173 bool operator!=(const T& value, const ScopedGeneric<T, Traits>& scoped) { | |
174 return value != scoped.get(); | |
175 } | |
176 | |
177 } // namespace base | |
178 | |
179 #endif // BASE_SCOPED_GENERIC_H_ | |
OLD | NEW |