xref: /aosp_15_r20/external/oboe/include/oboe/ResultWithValue.h (revision 05767d913155b055644481607e6fa1e35e2fe72c)
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