1 /* 2 * Copyright (C) 2018 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 OBOE_RESULT_WITH_VALUE_H 18 #define OBOE_RESULT_WITH_VALUE_H 19 20 #include "oboe/Definitions.h" 21 #include <iostream> 22 #include <sstream> 23 24 namespace oboe { 25 26 /** 27 * A ResultWithValue can store both the result of an operation (either OK or an error) and a value. 28 * 29 * It has been designed for cases where the caller needs to know whether an operation succeeded and, 30 * if it did, a value which was obtained during the operation. 31 * 32 * For example, when reading from a stream the caller needs to know the result of the read operation 33 * and, if it was successful, how many frames were read. Note that ResultWithValue can be evaluated 34 * as a boolean so it's simple to check whether the result is OK. 35 * 36 * <code> 37 * ResultWithValue<int32_t> resultOfRead = myStream.read(&buffer, numFrames, timeoutNanoseconds); 38 * 39 * if (resultOfRead) { 40 * LOGD("Frames read: %d", resultOfRead.value()); 41 * } else { 42 * LOGD("Error reading from stream: %s", resultOfRead.error()); 43 * } 44 * </code> 45 */ 46 template <typename T> 47 class ResultWithValue { 48 public: 49 50 /** 51 * Construct a ResultWithValue containing an error result. 52 * 53 * @param error The error 54 */ ResultWithValue(oboe::Result error)55 ResultWithValue(oboe::Result error) 56 : mValue{} 57 , mError(error) {} 58 59 /** 60 * Construct a ResultWithValue containing an OK result and a value. 61 * 62 * @param value the value to store 63 */ ResultWithValue(T value)64 explicit ResultWithValue(T value) 65 : mValue(value) 66 , mError(oboe::Result::OK) {} 67 68 /** 69 * Get the result. 70 * 71 * @return the result 72 */ error()73 oboe::Result error() const { 74 return mError; 75 } 76 77 /** 78 * Get the value 79 * @return 80 */ value()81 T value() const { 82 return mValue; 83 } 84 85 /** 86 * @return true if OK 87 */ 88 explicit operator bool() const { return mError == oboe::Result::OK; } 89 90 /** 91 * Quick way to check for an error. 92 * 93 * The caller could write something like this: 94 * <code> 95 * if (!result) { printf("Got error %s\n", convertToText(result.error())); } 96 * </code> 97 * 98 * @return true if an error occurred 99 */ 100 bool operator !() const { return mError != oboe::Result::OK; } 101 102 /** 103 * Implicitly convert to a Result. This enables easy comparison with Result values. Example: 104 * 105 * <code> 106 * ResultWithValue result = openStream(); 107 * if (result == Result::ErrorNoMemory){ // tell user they're out of memory } 108 * </code> 109 */ Result()110 operator Result() const { 111 return mError; 112 } 113 114 /** 115 * Create a ResultWithValue from a number. If the number is positive the ResultWithValue will 116 * have a result of Result::OK and the value will contain the number. If the number is negative 117 * the result will be obtained from the negative number (numeric error codes can be found in 118 * AAudio.h) and the value will be null. 119 * 120 */ createBasedOnSign(T numericResult)121 static ResultWithValue<T> createBasedOnSign(T numericResult){ 122 123 // Ensure that the type is either an integer or float 124 static_assert(std::is_arithmetic<T>::value, 125 "createBasedOnSign can only be called for numeric types (int or float)"); 126 127 if (numericResult >= 0){ 128 return ResultWithValue<T>(numericResult); 129 } else { 130 return ResultWithValue<T>(static_cast<Result>(numericResult)); 131 } 132 } 133 134 private: 135 const T mValue; 136 const oboe::Result mError; 137 }; 138 139 /** 140 * If the result is `OK` then return the value, otherwise return a human-readable error message. 141 */ 142 template <typename T> 143 std::ostream& operator<<(std::ostream &strm, const ResultWithValue<T> &result) { 144 if (!result) { 145 strm << convertToText(result.error()); 146 } else { 147 strm << result.value(); 148 } 149 return strm; 150 } 151 152 } // namespace oboe 153 154 155 #endif //OBOE_RESULT_WITH_VALUE_H 156