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