Chromium Code Reviews| Index: base/scoped_nullable_generic.h |
| diff --git a/base/scoped_nullable_generic.h b/base/scoped_nullable_generic.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..297b40036aba79d3c2e9954b4eaeb50cfe775714 |
| --- /dev/null |
| +++ b/base/scoped_nullable_generic.h |
| @@ -0,0 +1,177 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#ifndef BASE_SCOPED_NULLABLE_GENERIC_H_ |
| +#define BASE_SCOPED_NULLABLE_GENERIC_H_ |
| + |
| +#include <stdlib.h> |
| + |
| +#include "base/compiler_specific.h" |
| +#include "base/move.h" |
| + |
| +namespace base { |
| + |
| +// This class acts like ScopedPtr with a custom deleter (although is slightly |
| +// less fancy in some of the more escoteric respects) except that it keeps a |
| +// copy of the object rather than a pointer, and we require that the contained |
| +// object has some kind of "null" value. |
| +// |
| +// It is inteded that you will typedef this class with an appropriate deleter |
|
viettrungluu
2014/03/10 17:35:56
s/inteded/intended/
|
| +// to implement clean up tasks for objects that act like pointers from a |
| +// resource management standpoint but aren't, such as file descriptors and |
| +// various types of operating system handles. Using scoped_ptr for these |
| +// things requires that you keep a pointer to the handle valid for the lifetime |
| +// of the scoper (which is easy to mess up). |
| +// |
| +// For an object to be able to be put into a ScopedNullableGeneric, it must |
| +// support standard copyable semantics and have a specific "null" value. The |
| +// traits must define a free function and also the value to assign for |
| +// default-constructed objects. |
| +// |
| +// struct FooScopedTraits { |
| +// // It's assumed that this is a fast inline function with little-to-no |
| +// // penalty for duplicate calls. This must be a static function even |
| +// // for stateful traits. |
| +// static int NullValue() { |
| +// return 0; |
| +// } |
| +// |
| +// // This free function will not be called if the object == NullValue()! |
| +// static void Free(int f) { |
| +// ::FreeFoo(f); |
| +// } |
| +// }; |
| +// |
| +// typedef ScopedNullableGeneric<int, FooScopedTraits> ScopedFoo; |
| +template<typename T, typename Traits> |
| +class ScopedNullableGeneric { |
| + MOVE_ONLY_TYPE_FOR_CPP_03(ScopedNullableGeneric, RValue) |
| + |
| + private: |
| + // This must be first since it's used inline below. |
| + // |
| + // Use the empty base class optimization to allow us to have a D |
| + // member, while avoiding any space overhead for it when D is an |
| + // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good |
| + // discussion of this technique. |
| + struct Data : public Traits { |
| + explicit Data(const T& in) : generic(in) {} |
| + Data(const T& in, const Traits& other) : Traits(other), generic(in) {} |
| + T generic; |
| + }; |
| + |
| + public: |
| + typedef T element_type; |
| + typedef Traits traits_type; |
| + |
| + ScopedNullableGeneric() : data_(traits_type::NullValue()) {} |
| + |
| + // Constructor. Takes responsibility for freeing the resource associated with |
| + // the object T. |
| + explicit ScopedNullableGeneric(const element_type& value) : data_(value) {} |
| + |
| + // Constructor. Allows initialization of a stateful traits object. |
| + ScopedNullableGeneric(const element_type& value, const traits_type& traits) |
| + : data_(value, traits) { |
| + } |
| + |
| + // Move constructor for C++03 move emulation. |
| + ScopedNullableGeneric(RValue rvalue) |
| + : data_(rvalue.object->release(), rvalue.object->get_traits()) { |
| + } |
| + |
| + ~ScopedNullableGeneric() { |
| + FreeIfNecessary(); |
| + } |
| + |
| + ScopedNullableGeneric& operator=(ScopedNullableGeneric rhs) { |
| + reset(rhs.release()); |
| + get_traits() = rhs.get_traits(); |
| + } |
| + |
| + // Frees the currently owned object, if any. Then takes ownership of a new |
| + // object, if given. Self-resets are not allowd as on scoped_ptr. See |
| + // http://crbug.com/162971 |
| + void reset(const element_type& value = traits_type::NullValue()) { |
| + if (data_.generic != traits_type::NullValue() && data_.generic == value) |
| + abort(); |
| + FreeIfNecessary(); |
| + data_.generic = value; |
| + } |
| + |
| + void swap(ScopedNullableGeneric& other) { |
| + // Standard swap idiom: 'using std::swap' ensures that std::swap is |
| + // present in the overload set, but we call swap unqualified so that |
| + // any more-specific overloads can be used, if available. |
| + using std::swap; |
| + swap(static_cast<Traits&>(data_), static_cast<Traits&>(other.data_)); |
| + swap(data_.generic, other.data_.generic); |
| + } |
| + |
| + // Release the object. The return value is the current object held by this |
| + // object. After this operation, this object will hold a null pointer, and |
|
viettrungluu
2014/03/10 17:35:56
s/pointer/value/
|
| + // will not own the object any more. |
| + element_type release() WARN_UNUSED_RESULT { |
| + element_type old_generic = data_.generic; |
| + data_.generic = traits_type::NullValue(); |
| + return old_generic; |
| + } |
| + |
| + const element_type& get() const { return data_.generic; } |
| + |
| + // Returns true if this object doesn't hold the special null value for the |
| + // associated data type. |
| + bool is_valid() const { return data_.generic != traits_type::NullValue(); } |
| + |
| + bool operator==(const element_type& value) const { |
| + return data_.generic == value; |
| + } |
| + bool operator!=(const element_type& value) const { |
| + return data_.generic != value; |
| + } |
| + |
| + Traits& get_traits() { return data_; } |
| + const Traits& get_traits() const { return data_; } |
| + |
| + private: |
| + void FreeIfNecessary() { |
| + if (data_.generic != traits_type::NullValue()) { |
| + data_.Free(data_.generic); |
| + data_.generic = traits_type::NullValue(); |
| + } |
| + } |
| + |
| + // Forbid comparison of scoped_ptr types. If U != T, it totally |
|
viettrungluu
2014/03/10 17:35:56
scoped_ptr?
|
| + // doesn't make sense, and if U == T, it still doesn't make sense |
| + // because you should never have the same object owned by two different |
| + // scoped_ptrs. |
| + template <typename T2, typename Traits2> bool operator==( |
| + const ScopedNullableGeneric<T2, Traits2>& p2) const; |
| + template <typename T2, typename Traits2> bool operator!=( |
| + const ScopedNullableGeneric<T2, Traits2>& p2) const; |
| + |
| + Data data_; |
| +}; |
| + |
| +template<class T, class Traits> |
| +void swap(const ScopedNullableGeneric<T, Traits>& a, |
| + const ScopedNullableGeneric<T, Traits>& b) { |
| + a.swap(b); |
| +} |
| + |
| +template<class T, class Traits> |
| +bool operator==(const T& value, |
| + const ScopedNullableGeneric<T, Traits>& scoped) { |
| + return value == scoped.get(); |
| +} |
| + |
| +template<class T, class Traits> |
| +bool operator!=(const T& value, |
| + const ScopedNullableGeneric<T, Traits>& scoped) { |
| + return value != scoped.get(); |
| +} |
| + |
| +} // namespace base |
| + |
| +#endif // BASE_SCOPED_NULLABLE_GENERIC_H_ |