1 // Copyright 2013 The Flutter 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 FLUTTER_FML_UNIQUE_OBJECT_H_
6 #define FLUTTER_FML_UNIQUE_OBJECT_H_
7
8 #include <utility>
9
10 #include "flutter/fml/compiler_specific.h"
11 #include "flutter/fml/logging.h"
12 #include "flutter/fml/macros.h"
13
14 namespace fml {
15
16 // struct UniqueFooTraits {
17 // // This function should be fast and inline.
18 // static int InvalidValue() { return 0; }
19 //
20 // // This function should be fast and inline.
21 // static bool IsValid(const T& value) { return value != InvalidValue(); }
22 //
23 // // This free function will not be called if f == InvalidValue()!
24 // static void Free(int f) { ::FreeFoo(f); }
25 // };
26
27 template <typename T, typename Traits>
28 class UniqueObject {
29 private:
30 // This must be first since it's used inline below.
31 //
32 // Use the empty base class optimization to allow us to have a Traits
33 // member, while avoiding any space overhead for it when Traits is an
34 // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good
35 // discussion of this technique.
36 struct Data : public Traits {
DataData37 explicit Data(const T& in) : generic(in) {}
DataData38 Data(const T& in, const Traits& other) : Traits(other), generic(in) {}
39
40 T generic;
41 };
42
43 public:
44 using element_type = T;
45 using traits_type = Traits;
46
UniqueObject()47 UniqueObject() : data_(Traits::InvalidValue()) {}
UniqueObject(const T & value)48 explicit UniqueObject(const T& value) : data_(value) {}
49
UniqueObject(const T & value,const Traits & traits)50 UniqueObject(const T& value, const Traits& traits) : data_(value, traits) {}
51
UniqueObject(UniqueObject && other)52 UniqueObject(UniqueObject&& other)
53 : data_(other.release(), other.get_traits()) {}
54
~UniqueObject()55 ~UniqueObject() { FreeIfNecessary(); }
56
57 UniqueObject& operator=(UniqueObject&& other) {
58 reset(other.release());
59 return *this;
60 }
61
62 void reset(const T& value = Traits::InvalidValue()) {
63 FML_CHECK(data_.generic == Traits::InvalidValue() ||
64 data_.generic != value);
65 FreeIfNecessary();
66 data_.generic = value;
67 }
68
swap(UniqueObject & other)69 void swap(UniqueObject& other) {
70 // Standard swap idiom: 'using std::swap' ensures that std::swap is
71 // present in the overload set, but we call swap unqualified so that
72 // any more-specific overloads can be used, if available.
73 using std::swap;
74 swap(static_cast<Traits&>(data_), static_cast<Traits&>(other.data_));
75 swap(data_.generic, other.data_.generic);
76 }
77
78 // Release the object. The return value is the current object held by this
79 // object. After this operation, this object will hold an invalid value, and
80 // will not own the object any more.
release()81 T release() FML_WARN_UNUSED_RESULT {
82 T old_generic = data_.generic;
83 data_.generic = Traits::InvalidValue();
84 return old_generic;
85 }
86
get()87 const T& get() const { return data_.generic; }
88
is_valid()89 bool is_valid() const { return Traits::IsValid(data_.generic); }
90
91 bool operator==(const T& value) const { return data_.generic == value; }
92
93 bool operator!=(const T& value) const { return data_.generic != value; }
94
get_traits()95 Traits& get_traits() { return data_; }
get_traits()96 const Traits& get_traits() const { return data_; }
97
98 private:
FreeIfNecessary()99 void FreeIfNecessary() {
100 if (data_.generic != Traits::InvalidValue()) {
101 data_.Free(data_.generic);
102 data_.generic = Traits::InvalidValue();
103 }
104 }
105
106 // Forbid comparison. If U != T, it totally doesn't make sense, and if U ==
107 // T, it still doesn't make sense because you should never have the same
108 // object owned by two different UniqueObject.
109 template <typename T2, typename Traits2>
110 bool operator==(const UniqueObject<T2, Traits2>& p2) const = delete;
111
112 template <typename T2, typename Traits2>
113 bool operator!=(const UniqueObject<T2, Traits2>& p2) const = delete;
114
115 Data data_;
116
117 FML_DISALLOW_COPY_AND_ASSIGN(UniqueObject);
118 };
119
120 template <class T, class Traits>
swap(const UniqueObject<T,Traits> & a,const UniqueObject<T,Traits> & b)121 void swap(const UniqueObject<T, Traits>& a, const UniqueObject<T, Traits>& b) {
122 a.swap(b);
123 }
124
125 template <class T, class Traits>
126 bool operator==(const T& value, const UniqueObject<T, Traits>& object) {
127 return value == object.get();
128 }
129
130 template <class T, class Traits>
131 bool operator!=(const T& value, const UniqueObject<T, Traits>& object) {
132 return !(value == object.get());
133 }
134
135 } // namespace fml
136
137 #endif // FLUTTER_FML_UNIQUE_OBJECT_H_
138