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.
5 #ifndef BASE_SCOPED_GENERIC_H_
6 #define BASE_SCOPED_GENERIC_H_
10 #include "base/compiler_specific.h"
11 #include "base/move.h"
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 "invalid" value.
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
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).
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.
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() {
45 // // This free function will not be called if f == InvalidValue()!
46 // static void Free(int f) {
51 // typedef ScopedGeneric<int, FooScopedTraits> ScopedFoo;
52 template<typename T
, typename Traits
>
54 MOVE_ONLY_TYPE_FOR_CPP_03(ScopedGeneric
, RValue
)
57 // This must be first since it's used inline below.
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
) {}
70 typedef T element_type
;
71 typedef Traits traits_type
;
73 ScopedGeneric() : data_(traits_type::InvalidValue()) {}
75 // Constructor. Takes responsibility for freeing the resource associated with
77 explicit ScopedGeneric(const element_type
& value
) : data_(value
) {}
79 // Constructor. Allows initialization of a stateful traits object.
80 ScopedGeneric(const element_type
& value
, const traits_type
& traits
)
81 : data_(value
, traits
) {
84 // Move constructor for C++03 move emulation.
85 ScopedGeneric(RValue rvalue
)
86 : data_(rvalue
.object
->release(), rvalue
.object
->get_traits()) {
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::InvalidValue()) {
97 if (data_
.generic
!= traits_type::InvalidValue() && data_
.generic
== value
)
100 data_
.generic
= value
;
103 void swap(ScopedGeneric
& 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.
108 swap(static_cast<Traits
&>(data_
), static_cast<Traits
&>(other
.data_
));
109 swap(data_
.generic
, other
.data_
.generic
);
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 value, and
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::InvalidValue();
121 const element_type
& get() const { return data_
.generic
; }
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::InvalidValue(); }
127 bool operator==(const element_type
& value
) const {
128 return data_
.generic
== value
;
130 bool operator!=(const element_type
& value
) const {
131 return data_
.generic
!= value
;
134 Traits
& get_traits() { return data_
; }
135 const Traits
& get_traits() const { return data_
; }
138 void FreeIfNecessary() {
139 if (data_
.generic
!= traits_type::InvalidValue()) {
140 data_
.Free(data_
.generic
);
141 data_
.generic
= traits_type::InvalidValue();
145 // Forbid comparison. If U != T, it totally doesn't make sense, and if U ==
146 // T, it still doesn't make sense because you should never have the same
147 // object owned by two different ScopedGenerics.
148 template <typename T2
, typename Traits2
> bool operator==(
149 const ScopedGeneric
<T2
, Traits2
>& p2
) const;
150 template <typename T2
, typename Traits2
> bool operator!=(
151 const ScopedGeneric
<T2
, Traits2
>& p2
) const;
156 template<class T
, class Traits
>
157 void swap(const ScopedGeneric
<T
, Traits
>& a
,
158 const ScopedGeneric
<T
, Traits
>& b
) {
162 template<class T
, class Traits
>
163 bool operator==(const T
& value
, const ScopedGeneric
<T
, Traits
>& scoped
) {
164 return value
== scoped
.get();
167 template<class T
, class Traits
>
168 bool operator!=(const T
& value
, const ScopedGeneric
<T
, Traits
>& scoped
) {
169 return value
!= scoped
.get();
174 #endif // BASE_SCOPED_GENERIC_H_