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