aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/core/src/firebase/firestore/util
diff options
context:
space:
mode:
authorGravatar rsgowman <rgowman@google.com>2018-03-19 10:19:20 -0400
committerGravatar GitHub <noreply@github.com>2018-03-19 10:19:20 -0400
commit529666594951b86604730a8b400f71d7eedd1e85 (patch)
treef645396ea3485cd838db13ee715816cbca1bc334 /Firestore/core/src/firebase/firestore/util
parent4e7296b080b9c8cea13e5e5eeee65f4312fb5e8a (diff)
Add Status and StatusOr (#935)
* Pull in status files from tensorflow * Add missing dependency to immutable library
Diffstat (limited to 'Firestore/core/src/firebase/firestore/util')
-rw-r--r--Firestore/core/src/firebase/firestore/util/CMakeLists.txt5
-rw-r--r--Firestore/core/src/firebase/firestore/util/firebase_assert.h11
-rw-r--r--Firestore/core/src/firebase/firestore/util/status.cc135
-rw-r--r--Firestore/core/src/firebase/firestore/util/status.h143
-rw-r--r--Firestore/core/src/firebase/firestore/util/statusor.cc41
-rw-r--r--Firestore/core/src/firebase/firestore/util/statusor.h322
-rw-r--r--Firestore/core/src/firebase/firestore/util/statusor_internals.h258
7 files changed, 910 insertions, 5 deletions
diff --git a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
index 3e32111..7a080d4 100644
--- a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
+++ b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
@@ -118,6 +118,11 @@ cc_library(
ordered_code.cc
ordered_code.h
secure_random.h
+ status.cc
+ status.h
+ statusor.cc
+ statusor.h
+ statusor_internals.h
string_util.cc
string_util.h
DEPENDS
diff --git a/Firestore/core/src/firebase/firestore/util/firebase_assert.h b/Firestore/core/src/firebase/firestore/util/firebase_assert.h
index 76768e6..20c8429 100644
--- a/Firestore/core/src/firebase/firestore/util/firebase_assert.h
+++ b/Firestore/core/src/firebase/firestore/util/firebase_assert.h
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include "Firestore/core/src/firebase/firestore/util/log.h"
+#include "absl/base/attributes.h"
#define FIREBASE_EXPAND_STRINGIFY_(X) #X
#define FIREBASE_EXPAND_STRINGIFY(X) FIREBASE_EXPAND_STRINGIFY_(X)
@@ -107,11 +108,11 @@ namespace firestore {
namespace util {
// A no-return helper function. To raise an assertion, use Macro instead.
-void FailAssert(const char* file,
- const char* func,
- const int line,
- const char* format,
- ...);
+ABSL_ATTRIBUTE_NORETURN void FailAssert(const char* file,
+ const char* func,
+ const int line,
+ const char* format,
+ ...);
} // namespace util
} // namespace firestore
diff --git a/Firestore/core/src/firebase/firestore/util/status.cc b/Firestore/core/src/firebase/firestore/util/status.cc
new file mode 100644
index 0000000..0863139
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/status.cc
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2015, 2018 Google
+ *
+ * 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/status.h"
+
+#include "Firestore/core/src/firebase/firestore/util/string_printf.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+Status::Status(FirestoreErrorCode code, absl::string_view msg) {
+ FIREBASE_ASSERT(code != FirestoreErrorCode::Ok);
+ state_ = std::unique_ptr<State>(new State);
+ state_->code = code;
+ state_->msg = static_cast<std::string>(msg);
+}
+
+void Status::Update(const Status& new_status) {
+ if (ok()) {
+ *this = new_status;
+ }
+}
+
+void Status::SlowCopyFrom(const State* src) {
+ if (src == nullptr) {
+ state_ = nullptr;
+ } else {
+ state_ = std::unique_ptr<State>(new State(*src));
+ }
+}
+
+const std::string& Status::empty_string() {
+ static std::string* empty = new std::string;
+ return *empty;
+}
+
+std::string Status::ToString() const {
+ if (state_ == nullptr) {
+ return "OK";
+ } else {
+ std::string result;
+ switch (code()) {
+ case FirestoreErrorCode::Cancelled:
+ result = "Cancelled";
+ break;
+ case FirestoreErrorCode::Unknown:
+ result = "Unknown";
+ break;
+ case FirestoreErrorCode::InvalidArgument:
+ result = "Invalid argument";
+ break;
+ case FirestoreErrorCode::DeadlineExceeded:
+ result = "Deadline exceeded";
+ break;
+ case FirestoreErrorCode::NotFound:
+ result = "Not found";
+ break;
+ case FirestoreErrorCode::AlreadyExists:
+ result = "Already exists";
+ break;
+ case FirestoreErrorCode::PermissionDenied:
+ result = "Permission denied";
+ break;
+ case FirestoreErrorCode::Unauthenticated:
+ result = "Unauthenticated";
+ break;
+ case FirestoreErrorCode::ResourceExhausted:
+ result = "Resource exhausted";
+ break;
+ case FirestoreErrorCode::FailedPrecondition:
+ result = "Failed precondition";
+ break;
+ case FirestoreErrorCode::Aborted:
+ result = "Aborted";
+ break;
+ case FirestoreErrorCode::OutOfRange:
+ result = "Out of range";
+ break;
+ case FirestoreErrorCode::Unimplemented:
+ result = "Unimplemented";
+ break;
+ case FirestoreErrorCode::Internal:
+ result = "Internal";
+ break;
+ case FirestoreErrorCode::Unavailable:
+ result = "Unavailable";
+ break;
+ case FirestoreErrorCode::DataLoss:
+ result = "Data loss";
+ break;
+ default:
+ result = StringPrintf("Unknown code(%d)", static_cast<int>(code()));
+ break;
+ }
+ result += ": ";
+ result += state_->msg;
+ return result;
+ }
+}
+
+void Status::IgnoreError() const {
+ // no-op
+}
+
+std::ostream& operator<<(std::ostream& os, const Status& x) {
+ os << x.ToString();
+ return os;
+}
+
+std::string StatusCheckOpHelperOutOfLine(const Status& v, const char* msg) {
+ FIREBASE_ASSERT(!v.ok());
+ std::string r("Non-OK-status: ");
+ r += msg;
+ r += " status: ";
+ r += v.ToString();
+ return r;
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/status.h b/Firestore/core/src/firebase/firestore/util/status.h
new file mode 100644
index 0000000..0a65aa3
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/status.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2015, 2018 Google
+ *
+ * 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 FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUS_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUS_H_
+
+#include <functional>
+#include <iosfwd>
+#include <memory>
+#include <string>
+
+#include "Firestore/core/include/firebase/firestore/firestore_errors.h"
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+/// Denotes success or failure of a call.
+class ABSL_MUST_USE_RESULT Status {
+ public:
+ /// Create a success status.
+ Status() {
+ }
+
+ /// \brief Create a status with the specified error code and msg as a
+ /// human-readable string containing more detailed information.
+ Status(FirestoreErrorCode code, absl::string_view msg);
+
+ /// Copy the specified status.
+ Status(const Status& s);
+ void operator=(const Status& s);
+
+ static Status OK() {
+ return Status();
+ }
+
+ /// Returns true iff the status indicates success.
+ bool ok() const {
+ return (state_ == nullptr);
+ }
+
+ FirestoreErrorCode code() const {
+ return ok() ? FirestoreErrorCode::Ok : state_->code;
+ }
+
+ const std::string& error_message() const {
+ return ok() ? empty_string() : state_->msg;
+ }
+
+ bool operator==(const Status& x) const;
+ bool operator!=(const Status& x) const;
+
+ /// \brief If `ok()`, stores `new_status` into `*this`. If `!ok()`,
+ /// preserves the current status, but may augment with additional
+ /// information about `new_status`.
+ ///
+ /// Convenient way of keeping track of the first error encountered.
+ /// Instead of:
+ /// `if (overall_status.ok()) overall_status = new_status`
+ /// Use:
+ /// `overall_status.Update(new_status);`
+ void Update(const Status& new_status);
+
+ /// \brief Return a string representation of this status suitable for
+ /// printing. Returns the string `"OK"` for success.
+ std::string ToString() const;
+
+ // Ignores any errors. This method does nothing except potentially suppress
+ // complaints from any tools that are checking that errors are not dropped on
+ // the floor.
+ void IgnoreError() const;
+
+ private:
+ static const std::string& empty_string();
+ struct State {
+ FirestoreErrorCode code;
+ std::string msg;
+ };
+ // OK status has a `NULL` state_. Otherwise, `state_` points to
+ // a `State` structure containing the error code and message(s)
+ std::unique_ptr<State> state_;
+
+ void SlowCopyFrom(const State* src);
+};
+
+inline Status::Status(const Status& s)
+ : state_((s.state_ == nullptr) ? nullptr : new State(*s.state_)) {
+}
+
+inline void Status::operator=(const Status& s) {
+ // The following condition catches both aliasing (when this == &s),
+ // and the common case where both s and *this are ok.
+ if (state_ != s.state_) {
+ SlowCopyFrom(s.state_.get());
+ }
+}
+
+inline bool Status::operator==(const Status& x) const {
+ return (this->state_ == x.state_) || (ToString() == x.ToString());
+}
+
+inline bool Status::operator!=(const Status& x) const {
+ return !(*this == x);
+}
+
+std::ostream& operator<<(std::ostream& os, const Status& x);
+
+typedef std::function<void(const Status&)> StatusCallback;
+
+extern std::string StatusCheckOpHelperOutOfLine(const Status& v,
+ const char* msg);
+
+#define STATUS_CHECK_OK(val) \
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION( \
+ val.ok(), val.ok(), StatusCheckOpHelperOutOfLine(val, #val).c_str())
+
+// DEBUG only version of STATUS_CHECK_OK. Compiler still parses 'val' even in
+// opt mode.
+#define STATUS_DCHECK_OK(val) \
+ FIREBASE_DEV_ASSERT_MESSAGE_WITH_EXPRESSION( \
+ val.ok(), val.ok(), StatusCheckOpHelperOutOfLine(val, #val).c_str())
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUS_H_
diff --git a/Firestore/core/src/firebase/firestore/util/statusor.cc b/Firestore/core/src/firebase/firestore/util/statusor.cc
new file mode 100644
index 0000000..be1e03a
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/statusor.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017, 2018 Google
+ *
+ * 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/statusor.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+namespace internal_statusor {
+
+void Helper::HandleInvalidStatusCtorArg(Status* status) {
+ const char* kMessage =
+ "An OK status is not a valid constructor argument to StatusOr<T>";
+ FIREBASE_DEV_ASSERT_MESSAGE(false, kMessage);
+ // Fall back to Internal for non-debug builds
+ *status = Status(FirestoreErrorCode::Internal, kMessage);
+}
+
+void Helper::Crash(const Status& status) {
+ FIREBASE_ASSERT_MESSAGE(
+ false, "Attempting to fetch value instead of handling error ",
+ status.ToString().c_str());
+}
+
+} // namespace internal_statusor
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/statusor.h b/Firestore/core/src/firebase/firestore/util/statusor.h
new file mode 100644
index 0000000..dc5644a
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/statusor.h
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2017, 2018 Google
+ *
+ * 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.
+ */
+
+// StatusOr<T> is the union of a Status object and a T
+// object. StatusOr models the concept of an object that is either a
+// usable value, or an error Status explaining why such a value is
+// not present. To this end, StatusOr<T> does not allow its Status
+// value to be Status::OK. Furthermore, the value of a StatusOr<T*>
+// must not be null. This is enforced by a debug check in most cases,
+// but even when it is not, clients must not set the value to null.
+//
+// The primary use-case for StatusOr<T> is as the return value of a
+// function which may fail.
+//
+// Example client usage for a StatusOr<T>, where T is not a pointer:
+//
+// StatusOr<float> result = DoBigCalculationThatCouldFail();
+// if (result.ok()) {
+// float answer = result.ValueOrDie();
+// printf("Big calculation yielded: %f", answer);
+// } else {
+// LOG(ERROR) << result.status();
+// }
+//
+// Example client usage for a StatusOr<T*>:
+//
+// StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg);
+// if (result.ok()) {
+// std::unique_ptr<Foo> foo(result.ValueOrDie());
+// foo->DoSomethingCool();
+// } else {
+// LOG(ERROR) << result.status();
+// }
+//
+// Example client usage for a StatusOr<std::unique_ptr<T>>:
+//
+// StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
+// if (result.ok()) {
+// std::unique_ptr<Foo> foo = std::move(result.ValueOrDie());
+// foo->DoSomethingCool();
+// } else {
+// LOG(ERROR) << result.status();
+// }
+//
+// Example factory implementation returning StatusOr<T*>:
+//
+// StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
+// if (arg <= 0) {
+// return tensorflow::InvalidArgument("Arg must be positive");
+// } else {
+// return new Foo(arg);
+// }
+// }
+//
+// Note that the assignment operators require that destroying the currently
+// stored value cannot invalidate the argument; in other words, the argument
+// cannot be an alias for the current value, or anything owned by the current
+// value.
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_H_
+
+#include <utility>
+
+#include "Firestore/core/include/firebase/firestore/firestore_errors.h"
+#include "Firestore/core/src/firebase/firestore/util/status.h"
+#include "Firestore/core/src/firebase/firestore/util/statusor_internals.h"
+#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+template <typename T>
+class ABSL_MUST_USE_RESULT StatusOr
+ : private internal_statusor::StatusOrData<T>,
+ private internal_statusor::TraitsBase<
+ std::is_copy_constructible<T>::value,
+ std::is_move_constructible<T>::value> {
+ template <typename U>
+ friend class StatusOr;
+
+ typedef internal_statusor::StatusOrData<T> Base;
+
+ public:
+ typedef T element_type;
+
+ // Constructs a new StatusOr with FirebaseErrorCode::Unknown status. This is
+ // marked 'explicit' to try to catch cases like 'return {};', where people
+ // think StatusOr<std::vector<int>> will be initialized with an empty vector,
+ // instead of a FirebaseErrorCode::Unknown status.
+ explicit StatusOr(); // NOLINT: allow explicit zero-parameter ctor
+
+ // StatusOr<T> will be copy constructible/assignable if T is copy
+ // constructible.
+ StatusOr(const StatusOr&) = default;
+ StatusOr& operator=(const StatusOr&) = default;
+
+ // StatusOr<T> will be move constructible/assignable if T is move
+ // constructible.
+ StatusOr(StatusOr&&) = default;
+ StatusOr& operator=(StatusOr&&) = default;
+
+ // Conversion copy/move constructor, T must be convertible from U.
+ // TODO(b/62186717): These should not participate in overload resolution if U
+ // is not convertible to T.
+ template <typename U>
+ StatusOr(const StatusOr<U>& other);
+ template <typename U>
+ StatusOr(StatusOr<U>&& other);
+
+ // Conversion copy/move assignment operator, T must be convertible from U.
+ template <typename U>
+ StatusOr& operator=(const StatusOr<U>& other);
+ template <typename U>
+ StatusOr& operator=(StatusOr<U>&& other);
+
+ // Constructs a new StatusOr with the given value. After calling this
+ // constructor, calls to ValueOrDie() will succeed, and calls to status() will
+ // return OK.
+ //
+ // NOTE: Not explicit - we want to use StatusOr<T> as a return type
+ // so it is convenient and sensible to be able to do 'return T()'
+ // when the return type is StatusOr<T>.
+ //
+ // REQUIRES: T is copy constructible.
+ StatusOr(const T& value); // NOLINT: allow non-explicit 1-param ctor
+
+ // Constructs a new StatusOr with the given non-ok status. After calling
+ // this constructor, calls to ValueOrDie() will CHECK-fail.
+ //
+ // NOTE: Not explicit - we want to use StatusOr<T> as a return
+ // value, so it is convenient and sensible to be able to do 'return
+ // Status()' when the return type is StatusOr<T>.
+ //
+ // REQUIRES: !status.ok(). This requirement is DCHECKed.
+ // In optimized builds, passing Status::OK() here will have the effect
+ // of passing tensorflow::error::INTERNAL as a fallback.
+ StatusOr(const Status& status); // NOLINT: allow non-explicit 1-param ctor
+ StatusOr& operator=(const Status& status);
+
+ // TODO(b/62186997): Add operator=(T) overloads.
+
+ // Similar to the `const T&` overload.
+ //
+ // REQUIRES: T is move constructible.
+ StatusOr(T&& value); // NOLINT: allow non-explicit 1-param ctor
+
+ // RValue versions of the operations declared above.
+ StatusOr(Status&& status); // NOLINT: allow non-explicit 1-param ctor
+ StatusOr& operator=(Status&& status);
+
+ // Returns this->status().ok()
+ bool ok() const {
+ return this->status_.ok();
+ }
+
+ // Returns a reference to our status. If this contains a T, then
+ // returns Status::OK().
+ const Status& status() const&;
+ Status status() &&;
+
+ // Returns a reference to our current value, or CHECK-fails if !this->ok().
+ //
+ // Note: for value types that are cheap to copy, prefer simple code:
+ //
+ // T value = statusor.ValueOrDie();
+ //
+ // Otherwise, if the value type is expensive to copy, but can be left
+ // in the StatusOr, simply assign to a reference:
+ //
+ // T& value = statusor.ValueOrDie(); // or `const T&`
+ //
+ // Otherwise, if the value type supports an efficient move, it can be
+ // used as follows:
+ //
+ // T value = std::move(statusor).ValueOrDie();
+ //
+ // The std::move on statusor instead of on the whole expression enables
+ // warnings about possible uses of the statusor object after the move.
+ // C++ style guide waiver for ref-qualified overloads granted in cl/143176389
+ // See go/ref-qualifiers for more details on such overloads.
+ const T& ValueOrDie() const&;
+ T& ValueOrDie() &;
+ const T&& ValueOrDie() const&&;
+ T&& ValueOrDie() &&;
+
+ T ConsumeValueOrDie() {
+ return std::move(ValueOrDie());
+ }
+
+ // Ignores any errors. This method does nothing except potentially suppress
+ // complaints from any tools that are checking that errors are not dropped on
+ // the floor.
+ void IgnoreError() const;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation details for StatusOr<T>
+
+template <typename T>
+StatusOr<T>::StatusOr() : Base(Status(FirestoreErrorCode::Unknown, "")) {
+}
+
+template <typename T>
+StatusOr<T>::StatusOr(const T& value) : Base(value) {
+}
+
+template <typename T>
+StatusOr<T>::StatusOr(const Status& status) : Base(status) {
+}
+
+template <typename T>
+StatusOr<T>& StatusOr<T>::operator=(const Status& status) {
+ this->Assign(status);
+ return *this;
+}
+
+template <typename T>
+StatusOr<T>::StatusOr(T&& value) : Base(std::move(value)) {
+}
+
+template <typename T>
+StatusOr<T>::StatusOr(Status&& status) : Base(std::move(status)) {
+}
+
+template <typename T>
+StatusOr<T>& StatusOr<T>::operator=(Status&& status) {
+ this->Assign(std::move(status));
+ return *this;
+}
+
+template <typename T>
+template <typename U>
+inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
+ : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {
+}
+
+template <typename T>
+template <typename U>
+inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
+ if (other.ok())
+ this->Assign(other.ValueOrDie());
+ else
+ this->Assign(other.status());
+ return *this;
+}
+
+template <typename T>
+template <typename U>
+inline StatusOr<T>::StatusOr(StatusOr<U>&& other)
+ : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {
+}
+
+template <typename T>
+template <typename U>
+inline StatusOr<T>& StatusOr<T>::operator=(StatusOr<U>&& other) {
+ if (other.ok()) {
+ this->Assign(std::move(other).ValueOrDie());
+ } else {
+ this->Assign(std::move(other).status());
+ }
+ return *this;
+}
+
+template <typename T>
+const Status& StatusOr<T>::status() const& {
+ return this->status_;
+}
+template <typename T>
+Status StatusOr<T>::status() && {
+ return ok() ? Status::OK() : std::move(this->status_);
+}
+
+template <typename T>
+const T& StatusOr<T>::ValueOrDie() const& {
+ this->EnsureOk();
+ return this->data_;
+}
+
+template <typename T>
+T& StatusOr<T>::ValueOrDie() & {
+ this->EnsureOk();
+ return this->data_;
+}
+
+template <typename T>
+const T&& StatusOr<T>::ValueOrDie() const&& {
+ this->EnsureOk();
+ return std::move(this->data_);
+}
+
+template <typename T>
+T&& StatusOr<T>::ValueOrDie() && {
+ this->EnsureOk();
+ return std::move(this->data_);
+}
+
+template <typename T>
+void StatusOr<T>::IgnoreError() const {
+ // no-op
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_H_
diff --git a/Firestore/core/src/firebase/firestore/util/statusor_internals.h b/Firestore/core/src/firebase/firestore/util/statusor_internals.h
new file mode 100644
index 0000000..d6c8de1
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/statusor_internals.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2017, 2018 Google
+ *
+ * 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 FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_INTERNALS_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_INTERNALS_H_
+
+#include <utility>
+
+#include "Firestore/core/src/firebase/firestore/util/status.h"
+#include "absl/base/attributes.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+namespace internal_statusor {
+
+class Helper {
+ public:
+ // Move type-agnostic error handling to the .cc.
+ static void HandleInvalidStatusCtorArg(Status*);
+ ABSL_ATTRIBUTE_NORETURN static void Crash(const Status& status);
+};
+
+// Construct an instance of T in `p` through placement new, passing Args... to
+// the constructor.
+// This abstraction is here mostly for the gcc performance fix.
+template <typename T, typename... Args>
+void PlacementNew(void* p, Args&&... args) {
+#if defined(__GNUC__) && !defined(__clang__)
+ // Teach gcc that 'p' cannot be null, fixing code size issues.
+ if (p == nullptr) __builtin_unreachable();
+#endif
+ new (p) T(std::forward<Args>(args)...);
+}
+
+// Helper base class to hold the data and all operations.
+// We move all this to a base class to allow mixing with the appropriate
+// TraitsBase specialization.
+template <typename T>
+class StatusOrData {
+ template <typename U>
+ friend class StatusOrData;
+
+ public:
+ StatusOrData() = delete;
+
+ StatusOrData(const StatusOrData& other) {
+ if (other.ok()) {
+ MakeValue(other.data_);
+ MakeStatus();
+ } else {
+ MakeStatus(other.status_);
+ }
+ }
+
+ StatusOrData(StatusOrData&& other) noexcept {
+ if (other.ok()) {
+ MakeValue(std::move(other.data_));
+ MakeStatus();
+ } else {
+ MakeStatus(std::move(other.status_));
+ }
+ }
+
+ template <typename U>
+ StatusOrData(const StatusOrData<U>& other) {
+ if (other.ok()) {
+ MakeValue(other.data_);
+ MakeStatus();
+ } else {
+ MakeStatus(other.status_);
+ }
+ }
+
+ template <typename U>
+ StatusOrData(StatusOrData<U>&& other) {
+ if (other.ok()) {
+ MakeValue(std::move(other.data_));
+ MakeStatus();
+ } else {
+ MakeStatus(std::move(other.status_));
+ }
+ }
+
+ explicit StatusOrData(const T& value) : data_(value) {
+ MakeStatus();
+ }
+ explicit StatusOrData(T&& value) : data_(std::move(value)) {
+ MakeStatus();
+ }
+
+ explicit StatusOrData(const Status& status) : status_(status) {
+ EnsureNotOk();
+ }
+ explicit StatusOrData(Status&& status) : status_(std::move(status)) {
+ EnsureNotOk();
+ }
+
+ StatusOrData& operator=(const StatusOrData& other) {
+ if (this == &other) return *this;
+ if (other.ok())
+ Assign(other.data_);
+ else
+ Assign(other.status_);
+ return *this;
+ }
+
+ StatusOrData& operator=(StatusOrData&& other) {
+ if (this == &other) return *this;
+ if (other.ok())
+ Assign(std::move(other.data_));
+ else
+ Assign(std::move(other.status_));
+ return *this;
+ }
+
+ ~StatusOrData() {
+ if (ok()) {
+ status_.~Status();
+ data_.~T();
+ } else {
+ status_.~Status();
+ }
+ }
+
+ void Assign(const T& value) {
+ if (ok()) {
+ data_.~T();
+ MakeValue(value);
+ } else {
+ MakeValue(value);
+ status_ = Status::OK();
+ }
+ }
+
+ void Assign(T&& value) {
+ if (ok()) {
+ data_.~T();
+ MakeValue(std::move(value));
+ } else {
+ MakeValue(std::move(value));
+ status_ = Status::OK();
+ }
+ }
+
+ void Assign(const Status& status) {
+ Clear();
+ status_ = status;
+ EnsureNotOk();
+ }
+
+ void Assign(Status&& status) {
+ Clear();
+ status_ = std::move(status);
+ EnsureNotOk();
+ }
+
+ bool ok() const {
+ return status_.ok();
+ }
+
+ protected:
+ // status_ will always be active after the constructor.
+ // We make it a union to be able to initialize exactly how we need without
+ // waste.
+ // Eg. in the copy constructor we use the default constructor of Status in
+ // the ok() path to avoid an extra Ref call.
+ union {
+ Status status_;
+ };
+
+ // data_ is active iff status_.ok()==true
+ struct Dummy {};
+ union {
+ // When T is const, we need some non-const object we can cast to void* for
+ // the placement new. dummy_ is that object.
+ Dummy dummy_;
+ T data_;
+ };
+
+ void Clear() {
+ if (ok()) data_.~T();
+ }
+
+ void EnsureOk() const {
+ if (!ok()) Helper::Crash(status_);
+ }
+
+ void EnsureNotOk() {
+ if (ok()) Helper::HandleInvalidStatusCtorArg(&status_);
+ }
+
+ // Construct the value (ie. data_) through placement new with the passed
+ // argument.
+ template <typename Arg>
+ void MakeValue(Arg&& arg) {
+ internal_statusor::PlacementNew<T>(&dummy_, std::forward<Arg>(arg));
+ }
+
+ // Construct the status (ie. status_) through placement new with the passed
+ // argument.
+ template <typename... Args>
+ void MakeStatus(Args&&... args) {
+ internal_statusor::PlacementNew<Status>(&status_,
+ std::forward<Args>(args)...);
+ }
+};
+
+// Helper base class to allow implicitly deleted constructors and assignment
+// operations in StatusOr.
+// TraitsBase will explicitly delete what it can't support and StatusOr will
+// inherit that behavior implicitly.
+template <bool Copy, bool Move>
+struct TraitsBase {
+ TraitsBase() = default;
+ TraitsBase(const TraitsBase&) = default;
+ TraitsBase(TraitsBase&&) = default;
+ TraitsBase& operator=(const TraitsBase&) = default;
+ TraitsBase& operator=(TraitsBase&&) = default;
+};
+
+template <>
+struct TraitsBase<false, true> {
+ TraitsBase() = default;
+ TraitsBase(const TraitsBase&) = delete;
+ TraitsBase(TraitsBase&&) = default;
+ TraitsBase& operator=(const TraitsBase&) = delete;
+ TraitsBase& operator=(TraitsBase&&) = default;
+};
+
+template <>
+struct TraitsBase<false, false> {
+ TraitsBase() = default;
+ TraitsBase(const TraitsBase&) = delete;
+ TraitsBase(TraitsBase&&) = delete;
+ TraitsBase& operator=(const TraitsBase&) = delete;
+ TraitsBase& operator=(TraitsBase&&) = delete;
+};
+
+} // namespace internal_statusor
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_INTERNALS_H_