forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
unique_object.h
137 lines (106 loc) · 4.16 KB
/
unique_object.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright 2018 The Flutter 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 FLUTTER_FML_UNIQUE_OBJECT_H_
#define FLUTTER_FML_UNIQUE_OBJECT_H_
#include <utility>
#include "lib/fxl/compiler_specific.h"
#include "lib/fxl/logging.h"
#include "lib/fxl/macros.h"
namespace fml {
// struct UniqueFooTraits {
// // This function should be fast an inline.
// static int InvalidValue() { return 0; }
//
// // This function should be fast an inline.
// static bool IsValid(const T& value) { return value != InvalidValue(); }
//
// // This free function will not be called if f == InvalidValue()!
// static void Free(int f) { ::FreeFoo(f); }
// };
template <typename T, typename Traits>
class UniqueObject {
private:
// This must be first since it's used inline below.
//
// Use the empty base class optimization to allow us to have a Traits
// member, while avoiding any space overhead for it when Traits 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:
using element_type = T;
using traits_type = Traits;
UniqueObject() : data_(Traits::InvalidValue()) {}
explicit UniqueObject(const T& value) : data_(value) {}
UniqueObject(const T& value, const Traits& traits) : data_(value, traits) {}
UniqueObject(UniqueObject&& other)
: data_(other.release(), other.get_traits()) {}
~UniqueObject() { FreeIfNecessary(); }
UniqueObject& operator=(UniqueObject&& other) {
reset(other.release());
return *this;
}
void reset(const T& value = Traits::InvalidValue()) {
FXL_CHECK(data_.generic == Traits::InvalidValue() ||
data_.generic != value);
FreeIfNecessary();
data_.generic = value;
}
void swap(UniqueObject& 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 an invalid value, and
// will not own the object any more.
T release() FXL_WARN_UNUSED_RESULT {
T old_generic = data_.generic;
data_.generic = Traits::InvalidValue();
return old_generic;
}
const T& get() const { return data_.generic; }
bool is_valid() const { return Traits::IsValid(data_.generic); }
bool operator==(const T& value) const { return data_.generic == value; }
bool operator!=(const T& 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::InvalidValue()) {
data_.Free(data_.generic);
data_.generic = Traits::InvalidValue();
}
}
// Forbid comparison. If U != T, it totally 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 UniqueObject.
template <typename T2, typename Traits2>
bool operator==(const UniqueObject<T2, Traits2>& p2) const = delete;
template <typename T2, typename Traits2>
bool operator!=(const UniqueObject<T2, Traits2>& p2) const = delete;
Data data_;
FXL_DISALLOW_COPY_AND_ASSIGN(UniqueObject);
};
template <class T, class Traits>
void swap(const UniqueObject<T, Traits>& a, const UniqueObject<T, Traits>& b) {
a.swap(b);
}
template <class T, class Traits>
bool operator==(const T& value, const UniqueObject<T, Traits>& object) {
return value == object.get();
}
template <class T, class Traits>
bool operator!=(const T& value, const UniqueObject<T, Traits>& object) {
return !(value == object.get());
}
} // namespace fml
#endif // FLUTTER_FML_UNIQUE_OBJECT_H_