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/macros.h" 14 15 namespace base { 16 17 // This class acts like unique_ptr 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 // unique_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 unique_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 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. Allows initialization from a ScopedGeneric rvalue. 85 ScopedGeneric(ScopedGeneric<T, Traits>&& rvalue) 86 : data_(rvalue.release(), rvalue.get_traits()) { 87 } 88 89 ~ScopedGeneric() { 90 FreeIfNecessary(); 91 } 92 93 // operator=. Allows assignment from a ScopedGeneric rvalue. 94 ScopedGeneric& operator=(ScopedGeneric<T, Traits>&& rvalue) { 95 reset(rvalue.release()); 96 return *this; 97 } 98 99 // Frees the currently owned object, if any. Then takes ownership of a new 100 // object, if given. Self-resets are not allowd as on unique_ptr. See 101 // http://crbug.com/162971 102 void reset(const element_type& value = traits_type::InvalidValue()) { 103 if (data_.generic != traits_type::InvalidValue() && data_.generic == value) 104 abort(); 105 FreeIfNecessary(); 106 data_.generic = value; 107 } 108 109 void swap(ScopedGeneric& other) { 110 // Standard swap idiom: 'using std::swap' ensures that std::swap is 111 // present in the overload set, but we call swap unqualified so that 112 // any more-specific overloads can be used, if available. 113 using std::swap; 114 swap(static_cast<Traits&>(data_), static_cast<Traits&>(other.data_)); 115 swap(data_.generic, other.data_.generic); 116 } 117 118 // Release the object. The return value is the current object held by this 119 // object. After this operation, this object will hold a null value, and 120 // will not own the object any more. 121 element_type release() WARN_UNUSED_RESULT { 122 element_type old_generic = data_.generic; 123 data_.generic = traits_type::InvalidValue(); 124 return old_generic; 125 } 126 127 const element_type& get() const { return data_.generic; } 128 129 // Returns true if this object doesn't hold the special null value for the 130 // associated data type. 131 bool is_valid() const { return data_.generic != traits_type::InvalidValue(); } 132 133 bool operator==(const element_type& value) const { 134 return data_.generic == value; 135 } 136 bool operator!=(const element_type& value) const { 137 return data_.generic != value; 138 } 139 140 Traits& get_traits() { return data_; } 141 const Traits& get_traits() const { return data_; } 142 143 private: 144 void FreeIfNecessary() { 145 if (data_.generic != traits_type::InvalidValue()) { 146 data_.Free(data_.generic); 147 data_.generic = traits_type::InvalidValue(); 148 } 149 } 150 151 // Forbid comparison. If U != T, it totally doesn't make sense, and if U == 152 // T, it still doesn't make sense because you should never have the same 153 // object owned by two different ScopedGenerics. 154 template <typename T2, typename Traits2> bool operator==( 155 const ScopedGeneric<T2, Traits2>& p2) const; 156 template <typename T2, typename Traits2> bool operator!=( 157 const ScopedGeneric<T2, Traits2>& p2) const; 158 159 Data data_; 160 161 DISALLOW_COPY_AND_ASSIGN(ScopedGeneric); 162 }; 163 164 template<class T, class Traits> 165 void swap(const ScopedGeneric<T, Traits>& a, 166 const ScopedGeneric<T, Traits>& b) { 167 a.swap(b); 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 template<class T, class Traits> 176 bool operator!=(const T& value, const ScopedGeneric<T, Traits>& scoped) { 177 return value != scoped.get(); 178 } 179 180 } // namespace base 181 182 #endif // BASE_SCOPED_GENERIC_H_ 183