sandboxed-api/sandboxed_api/util/statusor.h
Christian Blichmann 8faccffbad Update StatusOr<> and tests
Fixes some template issues that could lead to code not compiling when it
otherwise should.

PiperOrigin-RevId: 308809964
Change-Id: I9f2f9d4aff5f1a9cb967fb705a86fd7f49114f7a
2020-04-28 06:12:58 -07:00

233 lines
5.6 KiB
C++

// Copyright 2019 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.
// This file and it's implementation provide a custom fork of
// util/task/statusor.h. This will become obsolete and will be replaced once
// Abseil releases absl::Status.
#ifndef THIRD_PARTY_SAPI_UTIL_STATUSOR_H_
#define THIRD_PARTY_SAPI_UTIL_STATUSOR_H_
#include <initializer_list>
#include <utility>
#include "absl/base/internal/raw_logging.h"
#include "absl/base/attributes.h"
#include "absl/base/log_severity.h"
#include "absl/status/status.h"
#include "absl/types/variant.h"
#include "sandboxed_api/util/raw_logging.h"
namespace sapi {
template <typename T>
class ABSL_MUST_USE_RESULT StatusOr {
template <typename U>
friend class StatusOr;
public:
using element_type = T;
explicit StatusOr() : variant_(absl::UnknownError("")) {}
StatusOr(const StatusOr&) = default;
StatusOr& operator=(const StatusOr&) = default;
StatusOr(StatusOr&&) = default;
StatusOr& operator=(StatusOr&&) = default;
// Not implemented:
// template <typename U> StatusOr(const StatusOr<U>& other)
// template <typename U> StatusOr(StatusOr<U>&& other)
template <typename U>
StatusOr& operator=(const StatusOr<U>& other) {
if (other.ok()) {
variant_ = other.value();
} else {
variant_ = other.status();
}
return *this;
}
template <typename U>
StatusOr& operator=(StatusOr<U>&& other) {
if (other.ok()) {
variant_ = std::move(other).value();
} else {
variant_ = std::move(other).status();
}
return *this;
}
StatusOr(const T& value) : variant_(value) {}
StatusOr(const absl::Status& status) : variant_(status) { EnsureNotOk(); }
// Not implemented:
// template <typename U = T> StatusOr& operator=(U&& value)
StatusOr(T&& value) : variant_(std::move(value)) {}
StatusOr(absl::Status&& value) : variant_(std::move(value)) {}
StatusOr& operator=(absl::Status&& status) {
variant_ = std::move(status);
EnsureNotOk();
}
template <typename... Args>
explicit StatusOr(absl::in_place_t, Args&&... args)
: StatusOr(T(std::forward<Args>(args)...)) {}
template <typename U, typename... Args>
explicit StatusOr(absl::in_place_t, std::initializer_list<U> ilist,
Args&&... args)
: StatusOr(ilist, U(std::forward<Args>(args)...)) {}
explicit operator bool() const { return ok(); }
ABSL_MUST_USE_RESULT bool ok() const {
return absl::holds_alternative<T>(variant_);
}
const absl::Status& status() const& {
static const auto* ok_status = new absl::Status();
return ok() ? *ok_status : absl::get<absl::Status>(variant_);
}
absl::Status status() && {
return ok() ? absl::OkStatus()
: std::move(absl::get<absl::Status>(variant_));
}
const T& value() const& {
EnsureOk();
return absl::get<T>(variant_);
}
T& value() & {
EnsureOk();
return absl::get<T>(variant_);
}
const T&& value() const&& {
EnsureOk();
return absl::get<T>(std::move(variant_));
}
T&& value() && {
EnsureOk();
return absl::get<T>(std::move(variant_));
}
const T& ValueOrDie() const& {
EnsureOk();
return absl::get<T>(variant_);
}
T& ValueOrDie() & {
EnsureOk();
return absl::get<T>(variant_);
}
T&& ValueOrDie() && {
EnsureOk();
return absl::get<T>(std::move(variant_));
}
const T& operator*() const& {
EnsureOk();
return absl::get<T>(variant_);
}
T& operator*() & {
EnsureOk();
return absl::get<T>(variant_);
}
const T&& operator*() const&& {
EnsureOk();
return absl::get<T>(std::move(variant_));
}
T&& operator*() && {
EnsureOk();
return absl::get<T>(std::move(variant_));
}
const T* operator->() const {
EnsureOk();
return &absl::get<T>(variant_);
}
T* operator->() {
EnsureOk();
return &absl::get<T>(variant_);
}
template <typename U>
T value_or(U&& default_value) const& {
if (ok()) {
return absl::get<T>(variant_);
}
return std::forward<U>(default_value);
}
template <typename U>
T value_or(U&& default_value) && {
if (ok()) {
return absl::get<T>(std::move(variant_));
}
return std::forward<U>(default_value);
}
void IgnoreError() const { /* no-op */
}
template <typename... Args>
T& emplace(Args&&... args) {
return variant_.template emplace<T>(std::forward<Args>(args)...);
}
template <typename U, typename... Args>
T& emplace(std::initializer_list<U> ilist, Args&&... args) {
return variant_.template emplace<T>(ilist, std::forward<Args>(args)...);
}
private:
void EnsureOk() const {
if (!ok()) {
// GoogleTest needs this exact error message for death tests to work.
SAPI_RAW_LOG(FATAL,
"Attempting to fetch value instead of handling error %s",
status().message());
}
}
void EnsureNotOk() const {
if (ok()) {
SAPI_RAW_LOG(
FATAL,
"An OK status is not a valid constructor argument to StatusOr<T>");
}
}
absl::variant<absl::Status, T> variant_;
};
} // namespace sapi
#endif // THIRD_PARTY_SAPI_UTIL_STATUSOR_H_