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