Refactor out optional and result
This commit is contained in:
parent
1bcfcff021
commit
76a21d266a
@ -1,6 +1,7 @@
|
|||||||
#ifndef ERROR_HPP
|
#ifndef ERROR_HPP
|
||||||
#define ERROR_HPP
|
#define ERROR_HPP
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -164,6 +165,8 @@ namespace detail {
|
|||||||
// Check condition in both debug. std::runtime_error on failure.
|
// Check condition in both debug. std::runtime_error on failure.
|
||||||
#define ASSERT(...) PHONY_USE(__VA_ARGS__)
|
#define ASSERT(...) PHONY_USE(__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern std::atomic_bool absorb_trace_exceptions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
154
src/utils/optional.hpp
Normal file
154
src/utils/optional.hpp
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
#ifndef OPTIONAL_HPP
|
||||||
|
#define OPTIONAL_HPP
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "utils/common.hpp"
|
||||||
|
#include "utils/error.hpp"
|
||||||
|
|
||||||
|
namespace cpptrace {
|
||||||
|
namespace detail {
|
||||||
|
struct nullopt_t {};
|
||||||
|
|
||||||
|
static constexpr nullopt_t nullopt;
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename T,
|
||||||
|
typename std::enable_if<!std::is_same<typename std::decay<T>::type, void>::value, int>::type = 0
|
||||||
|
>
|
||||||
|
class optional {
|
||||||
|
union {
|
||||||
|
char x;
|
||||||
|
T uvalue;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool holds_value = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
optional() noexcept {}
|
||||||
|
|
||||||
|
optional(nullopt_t) noexcept {}
|
||||||
|
|
||||||
|
~optional() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
optional(const optional& other) : holds_value(other.holds_value) {
|
||||||
|
if(holds_value) {
|
||||||
|
new (static_cast<void*>(std::addressof(uvalue))) T(other.uvalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
optional(optional&& other)
|
||||||
|
noexcept(std::is_nothrow_move_constructible<T>::value)
|
||||||
|
: holds_value(other.holds_value)
|
||||||
|
{
|
||||||
|
if(holds_value) {
|
||||||
|
new (static_cast<void*>(std::addressof(uvalue))) T(std::move(other.uvalue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
optional& operator=(const optional& other) {
|
||||||
|
optional copy(other);
|
||||||
|
swap(copy);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional& operator=(optional&& other)
|
||||||
|
noexcept(std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
if(other.holds_value) {
|
||||||
|
new (static_cast<void*>(std::addressof(uvalue))) T(std::move(other.uvalue));
|
||||||
|
holds_value = true;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename U = T,
|
||||||
|
typename std::enable_if<!std::is_same<typename std::decay<U>::type, optional<T>>::value, int>::type = 0
|
||||||
|
>
|
||||||
|
optional(U&& value) : holds_value(true) {
|
||||||
|
new (static_cast<void*>(std::addressof(uvalue))) T(std::forward<U>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename U = T,
|
||||||
|
typename std::enable_if<!std::is_same<typename std::decay<U>::type, optional<T>>::value, int>::type = 0
|
||||||
|
>
|
||||||
|
optional& operator=(U&& value) {
|
||||||
|
optional o(std::forward<U>(value));
|
||||||
|
swap(o);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional& operator=(nullopt_t) noexcept {
|
||||||
|
reset();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(optional& other) noexcept {
|
||||||
|
if(holds_value && other.holds_value) {
|
||||||
|
std::swap(uvalue, other.uvalue);
|
||||||
|
} else if(holds_value && !other.holds_value) {
|
||||||
|
new (&other.uvalue) T(std::move(uvalue));
|
||||||
|
uvalue.~T();
|
||||||
|
} else if(!holds_value && other.holds_value) {
|
||||||
|
new (static_cast<void*>(std::addressof(uvalue))) T(std::move(other.uvalue));
|
||||||
|
other.uvalue.~T();
|
||||||
|
}
|
||||||
|
std::swap(holds_value, other.holds_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_value() const {
|
||||||
|
return holds_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return holds_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
if(holds_value) {
|
||||||
|
uvalue.~T();
|
||||||
|
}
|
||||||
|
holds_value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD T& unwrap() & {
|
||||||
|
ASSERT(holds_value, "Optional does not contain a value");
|
||||||
|
return uvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD const T& unwrap() const & {
|
||||||
|
ASSERT(holds_value, "Optional does not contain a value");
|
||||||
|
return uvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD T&& unwrap() && {
|
||||||
|
ASSERT(holds_value, "Optional does not contain a value");
|
||||||
|
return std::move(uvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD const T&& unwrap() const && {
|
||||||
|
ASSERT(holds_value, "Optional does not contain a value");
|
||||||
|
return std::move(uvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
NODISCARD T value_or(U&& default_value) const & {
|
||||||
|
return holds_value ? uvalue : static_cast<T>(std::forward<U>(default_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
NODISCARD T value_or(U&& default_value) && {
|
||||||
|
return holds_value ? std::move(uvalue) : static_cast<T>(std::forward<U>(default_value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
129
src/utils/result.hpp
Normal file
129
src/utils/result.hpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#ifndef RESULT_HPP
|
||||||
|
#define RESULT_HPP
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "utils/common.hpp"
|
||||||
|
#include "utils/error.hpp"
|
||||||
|
#include "utils/optional.hpp"
|
||||||
|
|
||||||
|
namespace cpptrace {
|
||||||
|
namespace detail {
|
||||||
|
template<typename T, typename E, typename std::enable_if<!std::is_same<T, E>::value, int>::type = 0>
|
||||||
|
class Result {
|
||||||
|
union {
|
||||||
|
T value_;
|
||||||
|
E error_;
|
||||||
|
};
|
||||||
|
enum class member { value, error };
|
||||||
|
member active;
|
||||||
|
public:
|
||||||
|
Result(T&& value) : value_(std::move(value)), active(member::value) {}
|
||||||
|
Result(E&& error) : error_(std::move(error)), active(member::error) {
|
||||||
|
if(!absorb_trace_exceptions.load()) {
|
||||||
|
std::fprintf(stderr, "%s\n", unwrap_error().what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Result(T& value) : value_(T(value)), active(member::value) {}
|
||||||
|
Result(E& error) : error_(E(error)), active(member::error) {
|
||||||
|
if(!absorb_trace_exceptions.load()) {
|
||||||
|
std::fprintf(stderr, "%s\n", unwrap_error().what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Result(Result&& other) : active(other.active) {
|
||||||
|
if(other.active == member::value) {
|
||||||
|
new (&value_) T(std::move(other.value_));
|
||||||
|
} else {
|
||||||
|
new (&error_) E(std::move(other.error_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~Result() {
|
||||||
|
if(active == member::value) {
|
||||||
|
value_.~T();
|
||||||
|
} else {
|
||||||
|
error_.~E();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_value() const {
|
||||||
|
return active == member::value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_error() const {
|
||||||
|
return active == member::error;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD optional<T> value() const & {
|
||||||
|
return has_value() ? value_ : nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD optional<E> error() const & {
|
||||||
|
return is_error() ? error_ : nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD optional<T> value() && {
|
||||||
|
return has_value() ? std::move(value_) : nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD optional<E> error() && {
|
||||||
|
return is_error() ? std::move(error_) : nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD T& unwrap_value() & {
|
||||||
|
ASSERT(has_value(), "Result does not contain a value");
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD const T& unwrap_value() const & {
|
||||||
|
ASSERT(has_value(), "Result does not contain a value");
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD T unwrap_value() && {
|
||||||
|
ASSERT(has_value(), "Result does not contain a value");
|
||||||
|
return std::move(value_);
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD E& unwrap_error() & {
|
||||||
|
ASSERT(is_error(), "Result does not contain an error");
|
||||||
|
return error_;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD const E& unwrap_error() const & {
|
||||||
|
ASSERT(is_error(), "Result does not contain an error");
|
||||||
|
return error_;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD E unwrap_error() && {
|
||||||
|
ASSERT(is_error(), "Result does not contain an error");
|
||||||
|
return std::move(error_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
NODISCARD T value_or(U&& default_value) const & {
|
||||||
|
return has_value() ? value_ : static_cast<T>(std::forward<U>(default_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
NODISCARD T value_or(U&& default_value) && {
|
||||||
|
return has_value() ? std::move(value_) : static_cast<T>(std::forward<U>(default_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void drop_error() const {
|
||||||
|
if(is_error()) {
|
||||||
|
std::fprintf(stderr, "%s\n", unwrap_error().what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct monostate {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -2,7 +2,6 @@
|
|||||||
#define UTILS_HPP
|
#define UTILS_HPP
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@ -16,6 +15,8 @@
|
|||||||
|
|
||||||
#include "utils/common.hpp"
|
#include "utils/common.hpp"
|
||||||
#include "utils/error.hpp"
|
#include "utils/error.hpp"
|
||||||
|
#include "utils/optional.hpp"
|
||||||
|
#include "utils/result.hpp"
|
||||||
|
|
||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -147,260 +148,6 @@ namespace detail {
|
|||||||
static_assert(n_digits(11) == 2, "n_digits utility producing the wrong result");
|
static_assert(n_digits(11) == 2, "n_digits utility producing the wrong result");
|
||||||
static_assert(n_digits(1024) == 4, "n_digits utility producing the wrong result");
|
static_assert(n_digits(1024) == 4, "n_digits utility producing the wrong result");
|
||||||
|
|
||||||
struct nullopt_t {};
|
|
||||||
|
|
||||||
static constexpr nullopt_t nullopt;
|
|
||||||
|
|
||||||
template<
|
|
||||||
typename T,
|
|
||||||
typename std::enable_if<!std::is_same<typename std::decay<T>::type, void>::value, int>::type = 0
|
|
||||||
>
|
|
||||||
class optional {
|
|
||||||
union {
|
|
||||||
char x;
|
|
||||||
T uvalue;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool holds_value = false;
|
|
||||||
|
|
||||||
public:
|
|
||||||
optional() noexcept {}
|
|
||||||
|
|
||||||
optional(nullopt_t) noexcept {}
|
|
||||||
|
|
||||||
~optional() {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
optional(const optional& other) : holds_value(other.holds_value) {
|
|
||||||
if(holds_value) {
|
|
||||||
new (static_cast<void*>(std::addressof(uvalue))) T(other.uvalue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
optional(optional&& other)
|
|
||||||
noexcept(std::is_nothrow_move_constructible<T>::value)
|
|
||||||
: holds_value(other.holds_value)
|
|
||||||
{
|
|
||||||
if(holds_value) {
|
|
||||||
new (static_cast<void*>(std::addressof(uvalue))) T(std::move(other.uvalue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
optional& operator=(const optional& other) {
|
|
||||||
optional copy(other);
|
|
||||||
swap(copy);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
optional& operator=(optional&& other)
|
|
||||||
noexcept(std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value)
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
if(other.holds_value) {
|
|
||||||
new (static_cast<void*>(std::addressof(uvalue))) T(std::move(other.uvalue));
|
|
||||||
holds_value = true;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<
|
|
||||||
typename U = T,
|
|
||||||
typename std::enable_if<!std::is_same<typename std::decay<U>::type, optional<T>>::value, int>::type = 0
|
|
||||||
>
|
|
||||||
optional(U&& value) : holds_value(true) {
|
|
||||||
new (static_cast<void*>(std::addressof(uvalue))) T(std::forward<U>(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<
|
|
||||||
typename U = T,
|
|
||||||
typename std::enable_if<!std::is_same<typename std::decay<U>::type, optional<T>>::value, int>::type = 0
|
|
||||||
>
|
|
||||||
optional& operator=(U&& value) {
|
|
||||||
optional o(std::forward<U>(value));
|
|
||||||
swap(o);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
optional& operator=(nullopt_t) noexcept {
|
|
||||||
reset();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void swap(optional& other) noexcept {
|
|
||||||
if(holds_value && other.holds_value) {
|
|
||||||
std::swap(uvalue, other.uvalue);
|
|
||||||
} else if(holds_value && !other.holds_value) {
|
|
||||||
new (&other.uvalue) T(std::move(uvalue));
|
|
||||||
uvalue.~T();
|
|
||||||
} else if(!holds_value && other.holds_value) {
|
|
||||||
new (static_cast<void*>(std::addressof(uvalue))) T(std::move(other.uvalue));
|
|
||||||
other.uvalue.~T();
|
|
||||||
}
|
|
||||||
std::swap(holds_value, other.holds_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_value() const {
|
|
||||||
return holds_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit operator bool() const {
|
|
||||||
return holds_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
if(holds_value) {
|
|
||||||
uvalue.~T();
|
|
||||||
}
|
|
||||||
holds_value = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD T& unwrap() & {
|
|
||||||
ASSERT(holds_value, "Optional does not contain a value");
|
|
||||||
return uvalue;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD const T& unwrap() const & {
|
|
||||||
ASSERT(holds_value, "Optional does not contain a value");
|
|
||||||
return uvalue;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD T&& unwrap() && {
|
|
||||||
ASSERT(holds_value, "Optional does not contain a value");
|
|
||||||
return std::move(uvalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD const T&& unwrap() const && {
|
|
||||||
ASSERT(holds_value, "Optional does not contain a value");
|
|
||||||
return std::move(uvalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
NODISCARD T value_or(U&& default_value) const & {
|
|
||||||
return holds_value ? uvalue : static_cast<T>(std::forward<U>(default_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
NODISCARD T value_or(U&& default_value) && {
|
|
||||||
return holds_value ? std::move(uvalue) : static_cast<T>(std::forward<U>(default_value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
extern std::atomic_bool absorb_trace_exceptions;
|
|
||||||
|
|
||||||
template<typename T, typename E, typename std::enable_if<!std::is_same<T, E>::value, int>::type = 0>
|
|
||||||
class Result {
|
|
||||||
union {
|
|
||||||
T value_;
|
|
||||||
E error_;
|
|
||||||
};
|
|
||||||
enum class member { value, error };
|
|
||||||
member active;
|
|
||||||
public:
|
|
||||||
Result(T&& value) : value_(std::move(value)), active(member::value) {}
|
|
||||||
Result(E&& error) : error_(std::move(error)), active(member::error) {
|
|
||||||
if(!absorb_trace_exceptions.load()) {
|
|
||||||
std::fprintf(stderr, "%s\n", unwrap_error().what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Result(T& value) : value_(T(value)), active(member::value) {}
|
|
||||||
Result(E& error) : error_(E(error)), active(member::error) {
|
|
||||||
if(!absorb_trace_exceptions.load()) {
|
|
||||||
std::fprintf(stderr, "%s\n", unwrap_error().what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Result(Result&& other) : active(other.active) {
|
|
||||||
if(other.active == member::value) {
|
|
||||||
new (&value_) T(std::move(other.value_));
|
|
||||||
} else {
|
|
||||||
new (&error_) E(std::move(other.error_));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~Result() {
|
|
||||||
if(active == member::value) {
|
|
||||||
value_.~T();
|
|
||||||
} else {
|
|
||||||
error_.~E();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_value() const {
|
|
||||||
return active == member::value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_error() const {
|
|
||||||
return active == member::error;
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit operator bool() const {
|
|
||||||
return has_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD optional<T> value() const & {
|
|
||||||
return has_value() ? value_ : nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD optional<E> error() const & {
|
|
||||||
return is_error() ? error_ : nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD optional<T> value() && {
|
|
||||||
return has_value() ? std::move(value_) : nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD optional<E> error() && {
|
|
||||||
return is_error() ? std::move(error_) : nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD T& unwrap_value() & {
|
|
||||||
ASSERT(has_value(), "Result does not contain a value");
|
|
||||||
return value_;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD const T& unwrap_value() const & {
|
|
||||||
ASSERT(has_value(), "Result does not contain a value");
|
|
||||||
return value_;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD T unwrap_value() && {
|
|
||||||
ASSERT(has_value(), "Result does not contain a value");
|
|
||||||
return std::move(value_);
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD E& unwrap_error() & {
|
|
||||||
ASSERT(is_error(), "Result does not contain an error");
|
|
||||||
return error_;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD const E& unwrap_error() const & {
|
|
||||||
ASSERT(is_error(), "Result does not contain an error");
|
|
||||||
return error_;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODISCARD E unwrap_error() && {
|
|
||||||
ASSERT(is_error(), "Result does not contain an error");
|
|
||||||
return std::move(error_);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
NODISCARD T value_or(U&& default_value) const & {
|
|
||||||
return has_value() ? value_ : static_cast<T>(std::forward<U>(default_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
NODISCARD T value_or(U&& default_value) && {
|
|
||||||
return has_value() ? std::move(value_) : static_cast<T>(std::forward<U>(default_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
void drop_error() const {
|
|
||||||
if(is_error()) {
|
|
||||||
std::fprintf(stderr, "%s\n", unwrap_error().what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct monostate {};
|
|
||||||
|
|
||||||
// TODO: Re-evaluate use of off_t
|
// TODO: Re-evaluate use of off_t
|
||||||
template<typename T, typename std::enable_if<std::is_trivial<T>::value, int>::type = 0>
|
template<typename T, typename std::enable_if<std::is_trivial<T>::value, int>::type = 0>
|
||||||
Result<T, internal_error> load_bytes(std::FILE* object_file, off_t offset) {
|
Result<T, internal_error> load_bytes(std::FILE* object_file, off_t offset) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user