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