add expected.h (#2)
This commit is contained in:
98
src/expected.h
Normal file
98
src/expected.h
Normal file
@@ -0,0 +1,98 @@
|
||||
#ifndef EXPECTED_H
|
||||
#define EXPECTED_H
|
||||
|
||||
#include <exception>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
struct BadExpectedAccess : std::exception {
|
||||
const char* what() const noexcept override {
|
||||
return "bad access to `Expected` without expected value";
|
||||
}
|
||||
};
|
||||
|
||||
class Unexpected {
|
||||
public:
|
||||
explicit Unexpected(std::string_view err_msg) : err_msg_(err_msg) {}
|
||||
|
||||
std::string_view error() const noexcept { return err_msg_; }
|
||||
|
||||
private:
|
||||
std::string err_msg_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Expected {
|
||||
static_assert(!std::is_reference_v<T>,
|
||||
"Expected<T> does not support reference types");
|
||||
|
||||
public:
|
||||
Expected()
|
||||
requires(std::is_default_constructible_v<T>)
|
||||
: val_(std::in_place_index<0>) {}
|
||||
|
||||
Expected(const T& val) : val_(val) {}
|
||||
Expected(T&& val) : val_(std::move(val)) {}
|
||||
|
||||
Expected(const Unexpected& err) : val_(err) {}
|
||||
Expected(Unexpected&& err) : val_(std::move(err)) {}
|
||||
|
||||
bool has_value() const noexcept { return val_.index() == 0; }
|
||||
|
||||
explicit operator bool() const noexcept { return has_value(); }
|
||||
|
||||
T& value() & {
|
||||
if (!has_value()) throw BadExpectedAccess();
|
||||
return std::get<0>(val_);
|
||||
}
|
||||
|
||||
const T& value() const& {
|
||||
if (!has_value()) throw BadExpectedAccess();
|
||||
return std::get<0>(val_);
|
||||
}
|
||||
|
||||
T&& value() && {
|
||||
if (!has_value()) throw BadExpectedAccess();
|
||||
return std::move(std::get<0>(val_));
|
||||
}
|
||||
|
||||
const T&& value() const&& {
|
||||
if (!has_value()) throw BadExpectedAccess();
|
||||
return std::move(std::get<0>(val_));
|
||||
}
|
||||
|
||||
std::string_view error() const noexcept {
|
||||
return has_value() ? "" : std::get<1>(val_).error();
|
||||
}
|
||||
|
||||
private:
|
||||
std::variant<T, Unexpected> val_;
|
||||
};
|
||||
|
||||
template <>
|
||||
class Expected<void> {
|
||||
public:
|
||||
Expected() {}
|
||||
|
||||
Expected(const Unexpected& err) : err_(err) {}
|
||||
Expected(Unexpected&& err) : err_(std::move(err)) {}
|
||||
|
||||
bool has_value() const noexcept { return !err_.has_value(); }
|
||||
explicit operator bool() const noexcept { return has_value(); }
|
||||
|
||||
void value() const {
|
||||
if (!has_value()) throw BadExpectedAccess();
|
||||
}
|
||||
|
||||
std::string_view error() const noexcept {
|
||||
return err_.has_value() ? err_.value().error() : "";
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<Unexpected> err_;
|
||||
};
|
||||
|
||||
#endif // EXPECTED_H
|
||||
Reference in New Issue
Block a user