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