-
Notifications
You must be signed in to change notification settings - Fork 138
Expand file tree
/
Copy pathoptional.h
More file actions
212 lines (180 loc) · 6.3 KB
/
Copy pathoptional.h
File metadata and controls
212 lines (180 loc) · 6.3 KB
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/*
* Copyright 2018 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FIREBASE_APP_SRC_OPTIONAL_H_
#define FIREBASE_APP_SRC_OPTIONAL_H_
#include <cassert>
#include <cstdint>
#include <new>
#include <utility>
#include "app/src/include/firebase/internal/common.h"
namespace firebase {
// Optional<T> is a utility class to represent a value that can, but does not
// have to be present.
//
// This has a few different use cases. For return values, it allows values to be
// optionally returned without using pointers that might be null. In other
// words, a function that returns a pointer might always return a valid pointer,
// or it might sometimes return a valid pointer and sometimes return null.
// Returning an Optional makes it clear what the intention is.
//
// The other main use case is to be able to defer initialization of a value on
// the stack or in a struct. By using an optional you can leave a value
// uninitialized at creation and later initialize it when appropriate without
// having to default construct a value, or keep a null pointer to a value and
// later initializing it.
template <typename T>
class Optional {
public:
typedef T value_type;
// Initialize an empty Optional.
Optional() : has_value_(false) {}
// Copy contructor. If the other Optional has a value, it is copied into this
// Optional using its copy constructor.
Optional(const Optional& other) : has_value_(other.has_value()) {
if (other.has_value()) {
new (aligned_buffer()) value_type(other.value());
}
}
// Copy assignment. If the other Optional has a value, it is copy constructed
// or copy assigned into this Optional.
Optional& operator=(const Optional& other) {
if (other.has_value()) {
*this = other.value();
} else {
reset();
}
return *this;
}
#if defined(FIREBASE_USE_MOVE_OPERATORS)
// Move contructor. If the other Optional has a value, it is moved into this
// Optional using its move constructor.
Optional(Optional&& other) noexcept : has_value_(other.has_value_) {
if (has_value()) {
new (aligned_buffer()) value_type(std::move(other.value()));
other.reset();
}
}
// Move assignment. If the other Optional has a value, it is move constructed
// or move assigned into this Optional.
Optional& operator=(Optional&& other) noexcept {
if (other.has_value()) {
*this = std::move(other.value());
} else {
reset();
}
other.reset();
return *this;
}
#endif // FIREBASE_USE_MOVE_OPERATORS
// Initialize this Optional with the given value.
explicit Optional(const value_type& initial_value) : has_value_(true) {
new (aligned_buffer()) value_type(initial_value);
}
// Set value directly via copy constructor.
Optional& operator=(const value_type& other) {
if (has_value()) {
value() = other;
} else {
new (aligned_buffer()) value_type(other);
}
has_value_ = true;
return *this;
}
#if defined(FIREBASE_USE_MOVE_OPERATORS)
// Move construction with a given value.
explicit Optional(value_type&& initial_value) : has_value_(true) {
new (aligned_buffer()) value_type(std::move(initial_value));
}
// Set value directly via move constructor.
Optional& operator=(value_type&& other) {
if (has_value()) {
value() = std::move(other);
} else {
new (aligned_buffer()) value_type(std::move(other));
}
has_value_ = true;
return *this;
}
#endif // FIREBASE_USE_MOVE_OPERATORS
~Optional() { reset(); }
// Structure reference operator, to allow access to the members of the object
// held by the Optional.
const value_type* operator->() const { return &value(); }
value_type* operator->() { return &value(); }
// Dereference operator, to allow access to the members of the object held by
// the Optional.
const value_type& operator*() const { return value(); }
value_type& operator*() { return value(); }
// Returns true if this value contains a value, false otherwise.
bool has_value() const { return has_value_; }
// Returns the value held. Value must be present.
const value_type& value() const {
assert(has_value());
return *aligned_buffer();
}
// Returns the value held. Value must be present.
value_type& value() {
assert(has_value());
return *aligned_buffer();
}
// Returns the value held, or if empty, the default value provided.
value_type value_or(const value_type& default_value) const {
if (has_value()) {
return value();
} else {
return default_value;
}
}
// If this Optional contains a value, destruct it and mark this Optional as
// empty.
void reset() {
if (has_value()) {
value().~value_type();
has_value_ = false;
}
}
private:
const T* aligned_buffer() const {
return reinterpret_cast<const T*>(&buffer_);
}
T* aligned_buffer() { return reinterpret_cast<T*>(&buffer_); }
// Older versions of Visual Studio (2013 and prior) do not have support
// for alignof, but do have __alignof, so map it to use that if necessary.
#if (defined(_MSC_VER) && _MSC_VER <= 1800)
#define FIREBASE_ALIGNOF __alignof
#else
#define FIREBASE_ALIGNOF alignof
#endif // (defined(_MSC_VER) && _MSC_VER <= 1800)
typename FIREBASE_ALIGNED_STORAGE<sizeof(T), FIREBASE_ALIGNOF(T)>::type
buffer_;
#undef FIREBASE_ALIGNOF
bool has_value_;
};
template <typename T>
Optional<T> OptionalFromPointer(const T* pointer) {
return pointer ? Optional<T>(*pointer) : Optional<T>();
}
template <typename T>
bool operator==(const Optional<T>& lhs, const Optional<T>& rhs) {
return lhs.has_value() == rhs.has_value() &&
(!lhs.has_value() || (lhs.value() == rhs.value()));
}
template <typename T>
bool operator!=(const Optional<T>& lhs, const Optional<T>& rhs) {
return !(lhs == rhs);
}
} // namespace firebase
#endif // FIREBASE_APP_SRC_OPTIONAL_H_