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
14namespace 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
27template <typename T, typename Traits>
28class 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 {
37 explicit Data(const T& in) : generic(in) {}
38 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
47 UniqueObject() : data_(Traits::InvalidValue()) {}
48 explicit UniqueObject(const T& value) : data_(value) {}
49
50 UniqueObject(const T& value, const Traits& traits) : data_(value, traits) {}
51
52 UniqueObject(UniqueObject&& other)
53 : data_(other.release(), other.get_traits()) {}
54
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
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.
81 [[nodiscard]] T release() {
82 T old_generic = data_.generic;
83 data_.generic = Traits::InvalidValue();
84 return old_generic;
85 }
86
87 const T& get() const { return data_.generic; }
88
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
95 Traits& get_traits() { return data_; }
96 const Traits& get_traits() const { return data_; }
97
98 private:
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
120template <class T, class Traits>
121void swap(const UniqueObject<T, Traits>& a, const UniqueObject<T, Traits>& b) {
122 a.swap(b);
123}
124
125template <class T, class Traits>
126bool operator==(const T& value, const UniqueObject<T, Traits>& object) {
127 return value == object.get();
128}
129
130template <class T, class Traits>
131bool 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