blob: c6f849bd9a91f1ffdaad8854b651333a5c89fe32 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <functional>
#include <type_traits>
#include <variant>
namespace gfxstream {
template <typename E>
class unexpected;
template<class E>
unexpected(E) -> unexpected<E>;
#define ENABLE_IF(...) typename std::enable_if<__VA_ARGS__>::type* = nullptr
template <typename T, typename E>
class expected {
public:
constexpr expected() = default;
constexpr expected(const expected& rhs) = default;
constexpr expected(expected&& rhs) = default;
template <typename CopyT = T, ENABLE_IF(!std::is_void<CopyT>::value)>
constexpr expected(T&& v)
: mVariant(std::in_place_index<0>, std::forward<T>(v)) {}
template<class... Args, ENABLE_IF(std::is_constructible<T, Args&&...>::value)>
constexpr expected(std::in_place_t, Args&&... args)
: mVariant(std::in_place_index<0>, std::forward<Args>(args)...) {}
constexpr expected(const unexpected<E>& u)
: mVariant(std::in_place_index<1>, u.value()) {}
template<class OtherE = E, ENABLE_IF(std::is_constructible<E, const OtherE&>::value)>
constexpr expected(const unexpected<OtherE>& e)
: mVariant(std::in_place_index<1>, e.value()) {}
constexpr const T* operator->() const { return std::addressof(value()); }
constexpr T* operator->() { return std::addressof(value()); }
constexpr const T& operator*() const& { return value(); }
constexpr T& operator*() & { return value(); }
constexpr const T&& operator*() const&& { return std::move(std::get<T>(mVariant)); }
constexpr T&& operator*() && { return std::move(std::get<T>(mVariant)); }
constexpr bool has_value() const { return mVariant.index() == 0; }
constexpr bool ok() const { return has_value(); }
template <typename T2 = T, ENABLE_IF(!std::is_void<T>::value)>
constexpr const T& value() const& { return std::get<T>(mVariant); }
template <typename T2 = T, ENABLE_IF(!std::is_void<T>::value)>
constexpr T& value() & { return std::get<T>(mVariant); }
constexpr const T&& value() const&& { return std::move(std::get<T>(mVariant)); }
constexpr T&& value() && { return std::move(std::get<T>(mVariant)); }
constexpr const E& error() const& { return std::get<E>(mVariant); }
constexpr E& error() & { return std::get<E>(mVariant); }
constexpr const E&& error() const&& { return std::move(std::get<E>(mVariant)); }
constexpr E&& error() && { return std::move(std::get<E>(mVariant)); }
template <typename F,
typename NewE = std::remove_cv_t<std::invoke_result_t<F, E>>>
constexpr expected<T, NewE> transform_error(F&& function) {
if (ok()) {
if constexpr (std::is_void_v<T>) {
return expected<T, NewE>();
} else {
return expected<T, NewE>(std::in_place, value());
}
} else {
return unexpected(std::invoke(std::forward<F>(function), error()));
}
}
private:
std::variant<T, E> mVariant;
};
template <typename E>
class unexpected {
public:
constexpr unexpected(const unexpected&) = default;
template <typename T>
constexpr explicit unexpected(T&& e)
: mError(std::forward<T>(e)) {}
template<class... Args, ENABLE_IF(std::is_constructible<E, Args&&...>::value)>
constexpr explicit unexpected(std::in_place_t, Args&&... args)
: mError(std::forward<Args>(args)...) {}
constexpr const E& value() const& noexcept { return mError; }
constexpr E& value() & noexcept { return mError; }
constexpr const E&& value() const&& noexcept { return std::move(mError); }
constexpr E&& value() && noexcept { return std::move(mError); }
private:
E mError;
};
#define GFXSTREAM_EXPECT(x) \
({ \
auto local_expected = (x); \
if (!local_expected.ok()) { \
return gfxstream::unexpected(local_expected.error()); \
}; \
std::move(local_expected.value()); \
})
class Ok {};
} // namespace gfxstream