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