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 StatusOr { 30 public: 31 StatusOr() = default; 32 StatusOr(const Status status) : mStatus(status) { assert(!isOk(status)); } 33 StatusOr(const T& value) : mStatus(status::ok), mValue(value) {} 34 StatusOr(T&& value) : mStatus(status::ok), mValue(std::move(value)) {} 35 36 // Move constructor ok (if T supports move) 37 StatusOr(StatusOr&&) = default; 38 // Move assignment ok (if T supports move) 39 StatusOr& operator=(StatusOr&&) = default; 40 // Copy constructor ok (if T supports copy) 41 StatusOr(const StatusOr&) = default; 42 // Copy assignment ok (if T supports copy) 43 StatusOr& operator=(const StatusOr&) = default; 44 45 // Return const references to wrapped type 46 // It is an error to call value() when !isOk(status()) 47 const T& value() const & { return mValue; } 48 const T&& value() const && { return mValue; } 49 50 // Return rvalue references to wrapped type 51 // It is an error to call value() when !isOk(status()) 52 T& value() & { return mValue; } 53 T&& value() && { return mValue; } 54 55 // Return status assigned in constructor 56 const Status status() const { return mStatus; } 57 58 // Implict cast to Status 59 operator Status() const { return status(); } 60 61 private: 62 Status mStatus = status::undefined; 63 T mValue; 64 }; 65 66 template <typename T> 67 inline std::ostream& operator<<(std::ostream& os, const StatusOr<T>& s) { 68 return os << "StatusOr[status: " << s.status() << "]"; 69 } 70 71 #define ASSIGN_OR_RETURN_IMPL(tmp, lhs, stmt) \ 72 auto tmp = (stmt); \ 73 RETURN_IF_NOT_OK(tmp); \ 74 lhs = std::move(tmp.value()); 75 76 #define ASSIGN_OR_RETURN_CONCAT(line, lhs, stmt) \ 77 ASSIGN_OR_RETURN_IMPL(__CONCAT(_status_or_, line), lhs, stmt) 78 79 // Macro to allow exception-like handling of error return values. 80 // 81 // If the evaluation of stmt results in an error, return that error 82 // from the current function. Otherwise, assign the result to lhs. 83 // 84 // This macro supports both move and copy assignment operators. lhs 85 // may be either a new local variable or an existing non-const 86 // variable accessible in the current scope. 87 // 88 // Example usage: 89 // StatusOr<MyType> foo() { ... } 90 // 91 // ASSIGN_OR_RETURN(auto myVar, foo()); 92 // ASSIGN_OR_RETURN(myExistingVar, foo()); 93 // ASSIGN_OR_RETURN(myMemberVar, foo()); 94 #define ASSIGN_OR_RETURN(lhs, stmt) ASSIGN_OR_RETURN_CONCAT(__LINE__, lhs, stmt) 95 96 } // namespace netdutils 97 } // namespace android 98 99 #endif /* NETUTILS_STATUSOR_H */ 100