1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef NETUTILS_STATUSOR_H 18 #define NETUTILS_STATUSOR_H 19 20 #include <cassert> 21 #include "netdutils/Status.h" 22 23 namespace android { 24 namespace netdutils { 25 26 // Wrapper around a combination of Status and application value type. 27 // T may be any copyable or movable type. 28 template <typename T> 29 class [[nodiscard]] StatusOr { 30 public: 31 // Constructs a new StatusOr with status::undefined status. 32 // This is marked 'explicit' to try to catch cases like 'return {};', 33 // where people think StatusOr<std::vector<int>> will be initialized 34 // with an empty vector, instead of a status::undefined. 35 explicit StatusOr() = default; 36 37 // Implicit copy constructor and construction from T. 38 // NOLINTNEXTLINE(google-explicit-constructor) StatusOr(Status status)39 StatusOr(Status status) : mStatus(std::move(status)) { assert(!isOk(mStatus)); } 40 41 // Implicit construction from T. It is convenient and sensible to be able 42 // to do 'return T()' when the return type is StatusOr<T>. 43 // NOLINTNEXTLINE(google-explicit-constructor) StatusOr(const T & value)44 StatusOr(const T& value) : mStatus(status::ok), mValue(value) {} 45 // NOLINTNEXTLINE(google-explicit-constructor) StatusOr(T && value)46 StatusOr(T&& value) : mStatus(status::ok), mValue(std::move(value)) {} 47 48 // Move constructor ok (if T supports move) 49 StatusOr(StatusOr&&) noexcept = default; 50 // Move assignment ok (if T supports move) 51 StatusOr& operator=(StatusOr&&) noexcept = default; 52 // Copy constructor ok (if T supports copy) 53 StatusOr(const StatusOr&) = default; 54 // Copy assignment ok (if T supports copy) 55 StatusOr& operator=(const StatusOr&) = default; 56 57 // Returns a const reference to wrapped type. 58 // It is an error to call value() when !isOk(status()) value()59 const T& value() const & { return mValue; } value()60 const T&& value() const && { return mValue; } 61 62 // Returns an rvalue reference to wrapped type 63 // It is an error to call value() when !isOk(status()) 64 // 65 // If T is expensive to copy but supports efficient move, it can be moved 66 // out of a StatusOr as follows: 67 // T value = std::move(statusor).value(); value()68 T& value() & { return mValue; } value()69 T&& value() && { return mValue; } 70 71 // Returns the Status object assigned at construction time. status()72 const Status status() const { return mStatus; } 73 74 // Explicitly ignores the Status without triggering [[nodiscard]] errors. ignoreError()75 void ignoreError() const {} 76 77 // Implicit cast to Status. 78 // NOLINTNEXTLINE(google-explicit-constructor) Status()79 operator Status() const { return status(); } 80 81 private: 82 Status mStatus = status::undefined; 83 T mValue; 84 }; 85 86 template <typename T> 87 inline std::ostream& operator<<(std::ostream& os, const StatusOr<T>& s) { 88 return os << "StatusOr[status: " << s.status() << "]"; 89 } 90 91 #define ASSIGN_OR_RETURN_IMPL(tmp, lhs, stmt) \ 92 auto tmp = (stmt); \ 93 RETURN_IF_NOT_OK(tmp); \ 94 lhs = std::move(tmp.value()); 95 96 #define ASSIGN_OR_RETURN_CONCAT(line, lhs, stmt) \ 97 ASSIGN_OR_RETURN_IMPL(__CONCAT(_status_or_, line), lhs, stmt) 98 99 // Macro to allow exception-like handling of error return values. 100 // 101 // If the evaluation of stmt results in an error, return that error 102 // from the current function. Otherwise, assign the result to lhs. 103 // 104 // This macro supports both move and copy assignment operators. lhs 105 // may be either a new local variable or an existing non-const 106 // variable accessible in the current scope. 107 // 108 // Example usage: 109 // StatusOr<MyType> foo() { ... } 110 // 111 // ASSIGN_OR_RETURN(auto myVar, foo()); 112 // ASSIGN_OR_RETURN(myExistingVar, foo()); 113 // ASSIGN_OR_RETURN(myMemberVar, foo()); 114 #define ASSIGN_OR_RETURN(lhs, stmt) ASSIGN_OR_RETURN_CONCAT(__LINE__, lhs, stmt) 115 116 } // namespace netdutils 117 } // namespace android 118 119 #endif /* NETUTILS_STATUSOR_H */ 120