MotorControlModuleSDFM_TMS3.../Projects/EFC_Application/UMLibrary/common/Result.hh

379 lines
8.3 KiB
C++
Raw Permalink Normal View History

/*
* Result.hpp
*
* Created on: 11 May 2023
* Author: malyarenko
*/
/*
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> C++ <EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> header-only <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Result
* https://github.com/oktal/result
*/
#ifndef UMLIBRARY_COMMON_RESULT_HH_
#define UMLIBRARY_COMMON_RESULT_HH_
#include <cstddef>
#include <cstdlib>
#include <utility>
#include <new>
#include <type_traits>
#include "Error.hh"
namespace result {
namespace types {
template< typename T >
struct Ok {
#if __cplusplus >= 201103L
Ok(T&& value)
: value(std::move(value)) { }
#else
Ok(T& value)
: value(value) { }
#endif
T value;
};
template<>
struct Ok<void> { };
template< typename E >
struct Err {
#if __cplusplus >= 201103L
Err(E&& value)
: value(std::move(value)) { }
#else
Err(E& value)
: value(value) { }
#endif
Err(const E& value)
: value(value) { }
E value;
};
} /* namespace types */
} /* namespace result */
inline result::types::Ok<void> Ok() {
return result::types::Ok<void>();
}
#if __cplusplus >= 201103L
template<typename T, typename CleanT = typename std::decay<T>::type>
result::types::Ok<CleanT> Ok(T&& value) {
return result::types::Ok<CleanT>(std::forward<CleanT>(value));
}
template<typename E, typename CleanE = typename std::decay<E>::type>
result::types::Err<CleanE> Err(E&& value) {
return result::types::Err<CleanE>(std::forward<CleanE>(value));
}
#else
template<typename T, typename CleanT = typename std::tr1::decay<T>::type>
result::types::Ok<CleanT> Ok(T& value) {
return result::types::Ok<CleanT>(value);
}
template<typename E, typename CleanE = typename std::tr1::decay<E>::type>
result::types::Err<CleanE> Err(E& value) {
return result::types::Err<CleanE>(value);
}
#endif
namespace result {
namespace storage {
struct OkTag { };
struct ErrTag { };
template< typename T, typename E >
class Storage {
public:
Storage()
: initialized(false) { }
void construct(result::types::Ok<T> ok) {
new (&storage) T(ok.value);
initialized = true;
}
void construct(result::types::Err<E> err) {
new (&storage) E(err.value);
initialized = true;
}
#if __cplusplus >= 201103L
template< typename U >
void constructRaw(U&& value) {
typedef typename std::decay<U>::type CleanU;
new (&storage) CleanU(std::forward<U>(value));
initialized = true;
}
#else
template< typename U >
void constructRaw(U& value) {
typedef typename std::tr1::decay<U>::type CleanU;
new (&storage) CleanU(value);
initialized = true;
}
#endif
template< typename U >
const U& get() const {
return *reinterpret_cast< const U * >(&storage);
}
template< typename U >
U& get() {
return *reinterpret_cast< U * >(&storage);
}
void destroy(OkTag) {
if (initialized) {
get<T>().~T();
initialized = false;
}
}
void destroy(ErrTag) {
if (initialized) {
get<E>().~E();
initialized = false;
}
}
private:
static constexpr std::size_t Size = sizeof(T) > sizeof(E) ? sizeof(T) : sizeof(E);
static constexpr std::size_t Align = alignof(T) > alignof(E) ? alignof(T) : alignof(E);
#if __cplusplus >= 201103L
typedef typename std::aligned_storage<Size, Align>::type type;
type storage;
#else
unsigned long storage[1+Size/2];
#endif
bool initialized;
};
template< typename E >
struct Storage< void, E > {
#if __cplusplus >= 201103L
typedef typename std::aligned_storage<sizeof(E), alignof(E)>::type type;
type storage;
#else
unsigned long storage[1+sizeof(E)/2];
#endif
void construct(result::types::Ok<void>) {
initialized = true;
}
void construct(result::types::Err<E> err) {
new (&storage) E(err.value);
initialized = true;
}
#if __cplusplus >= 201103L
template< typename U >
void constructRaw(U&& value) {
typedef typename std::decay<U>::type CleanU;
new (&storage) CleanU(std::forward<U>(value));
initialized = true;
}
#else
template< typename U >
void constructRaw(U& value) {
typedef typename std::tr1::decay<U>::type CleanU;
new (&storage) CleanU(value);
initialized = true;
}
#endif
void destroy(OkTag) {
initialized = false;
}
void destroy(ErrTag) {
if (initialized) {
get<E>().~E();
initialized = false;
}
}
template<typename U>
const U& get() const {
return *reinterpret_cast< const U * >(&storage);
}
template<typename U>
U& get() {
return *reinterpret_cast< U * >(&storage);
}
bool initialized;
};
template< typename T, typename E >
struct Constructor {
static void copy(const Storage<T, E>& src, Storage<T, E>& dst, OkTag) {
dst.constructRaw(src.template get<T>());
}
static void copy(const Storage<T, E>& src, Storage<T, E>& dst, ErrTag) {
dst.constructRaw(src.template get<E>());
}
#if __cplusplus >= 201103L
static void move(Storage<T, E>&& src, Storage<T, E>& dst, OkTag) {
dst.constructRaw(std::move(src.template get<T>()));
src.destroy(OkTag());
}
static void move(Storage<T, E>&& src, Storage<T, E>& dst, ErrTag) {
dst.constructRaw(std::move(src.template get<E>()));
src.destroy(ErrTag());
}
#endif
};
template<typename E>
struct Constructor<void, E> {
static void copy(const Storage<void, E>& src, Storage<void, E>& dst, OkTag) { }
static void copy(const Storage<void, E>& src, Storage<void, E>& dst, ErrTag) {
dst.constructRaw(src.template get<E>());
}
#if __cplusplus >= 201103L
static void move(Storage<void, E>&& src, Storage<void, E>& dst, OkTag) { }
static void move(Storage<void, E>&& src, Storage<void, E>& dst, ErrTag) {
dst.constructRaw(std::move(src.template get<E>()));
src.destroy(ErrTag());
}
#endif
};
} /* namespace storage */
} /* namespace result */
template< typename T, typename E >
class Result {
public:
#if __cplusplus >= 201103L
static_assert(!std::is_same<E, void>::value, "void error type is not allowed");
#endif
typedef result::storage::Storage<T, E> storage_type;
#if __cplusplus >= 201103L
Result(result::types::Ok<T> ok)
: ok(true)
{
storage.construct(std::move(ok));
}
Result(result::types::Err<E> err)
: ok(false)
{
storage.construct(std::move(err));
}
Result(Result&& other) {
if (other.isOk()) {
result::storage::Constructor<T, E>::move(std::move(other.storage), storage, result::storage::OkTag());
ok = true;
} else {
result::storage::Constructor<T, E>::move(std::move(other.storage), storage, result::storage::ErrTag());
ok = false;
}
}
#else
Result(result::types::Ok<T> ok)
: ok(true)
{
storage.construct(ok);
}
Result(result::types::Err<E> err)
: ok(false)
{
storage.construct(err);
}
#endif
Result(const Result& other) {
if (other.isOk()) {
result::storage::Constructor<T, E>::copy(other.storage, storage, result::storage::OkTag());
ok = true;
} else {
result::storage::Constructor<T, E>::copy(other.storage, storage, result::storage::ErrTag());
ok = false;
}
}
~Result() {
if (ok) {
storage.destroy(result::storage::OkTag());
} else {
storage.destroy(result::storage::ErrTag());
}
}
bool isOk() const {
return ok;
}
bool isErr() const {
return !ok;
}
#if __cplusplus >= 201103L
template< typename U = T >
typename std::enable_if<!std::is_same<U, void>::value, U >::type
unwrap() const {
if (isOk()) {
return storage.template get<U>();
}
std::abort();
}
#else
template< typename U = T >
typename std::tr1::enable_if<!std::tr1::is_same<U, void>::value, U >::type
unwrap() const {
if (isOk()) {
return storage.template get<U>();
}
std::abort();
}
#endif
E unwrapErr() const {
if (isErr()) {
return storage.template get<E>();
}
std::abort();
}
private:
bool ok;
storage_type storage;
};
#endif /* UMLIBRARY_COMMON_RESULT_HH_ */