234 lines
5.2 KiB
C++
234 lines
5.2 KiB
C++
#pragma once
|
|||
|
|
|
||
|
|
#include "Util2.h"
|
||
|
|
#include <string>
|
||
|
|
#include <type_traits>
|
||
|
|
|
||
|
|
namespace pymol
|
||
|
|
{
|
||
|
|
struct Void {
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Expressive error handling alternative
|
||
|
|
*/
|
||
|
|
class Error
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
enum Code {
|
||
|
|
DEFAULT,
|
||
|
|
QUIET,
|
||
|
|
MEMORY,
|
||
|
|
INCENTIVE_ONLY,
|
||
|
|
};
|
||
|
|
|
||
|
|
Error() {}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Construct from string
|
||
|
|
*/
|
||
|
|
explicit Error(std::string s)
|
||
|
|
: m_errMsg(std::move(s))
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Construct from error code.
|
||
|
|
*/
|
||
|
|
explicit Error(Code code)
|
||
|
|
: m_code(code)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Retrieves error message
|
||
|
|
* @return error message
|
||
|
|
*/
|
||
|
|
|
||
|
|
const std::string& what() const noexcept { return m_errMsg; }
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Error code
|
||
|
|
*/
|
||
|
|
Code code() const noexcept { return m_code; }
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Make an error instance with error code.
|
||
|
|
*/
|
||
|
|
template <Code C, typename... PrintableTs>
|
||
|
|
static Error make(PrintableTs&&... ts)
|
||
|
|
{
|
||
|
|
auto error = Error(join_to_string(std::forward<PrintableTs>(ts)...));
|
||
|
|
error.m_code = C;
|
||
|
|
return error;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
std::string m_errMsg;
|
||
|
|
Code m_code = DEFAULT;
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Creates Error message
|
||
|
|
* @param ts collection of printable values to be joined
|
||
|
|
* into an error message
|
||
|
|
*/
|
||
|
|
template<typename... PrintableTs>
|
||
|
|
Error make_error(PrintableTs&&... ts)
|
||
|
|
{
|
||
|
|
return Error(join_to_string(std::forward<PrintableTs>(ts)...));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Class that expresses the expected result of a function
|
||
|
|
*/
|
||
|
|
|
||
|
|
template <typename ResultT=Void> class Result
|
||
|
|
{
|
||
|
|
|
||
|
|
public:
|
||
|
|
using type = ResultT;
|
||
|
|
|
||
|
|
Result() = default;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Constructor alternative that allows for convertible types
|
||
|
|
* param r result returned from function with a type convertible to ResultT
|
||
|
|
*/
|
||
|
|
|
||
|
|
Result(type r) : m_result(std::move(r)) {}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Constructor alternative that takes in pymol::Error. Value of expected type
|
||
|
|
* should not be taken at this point.
|
||
|
|
* @param e error object to express why value should not be used
|
||
|
|
*/
|
||
|
|
|
||
|
|
Result(Error e) : m_error{std::move(e)}, m_valid{false} {}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Construct from error code.
|
||
|
|
*/
|
||
|
|
Result(Error::Code code)
|
||
|
|
: m_error(code)
|
||
|
|
, m_valid{false}
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Determines whether the value of the expected type can be used.
|
||
|
|
*/
|
||
|
|
|
||
|
|
explicit operator bool() const noexcept { return m_valid; }
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Retrieves the underlying error object
|
||
|
|
*/
|
||
|
|
|
||
|
|
const Error& error() const noexcept { return m_error; }
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Rvalue reference to the underlying error object
|
||
|
|
*/
|
||
|
|
Error&& error_move() noexcept
|
||
|
|
{
|
||
|
|
assert(!m_valid);
|
||
|
|
return std::move(m_error);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Retrieves the value of the expected object
|
||
|
|
*/
|
||
|
|
|
||
|
|
ResultT& result() { return m_result; }
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Retrieves the value of the expected object
|
||
|
|
*/
|
||
|
|
|
||
|
|
const ResultT& result() const { return m_result; }
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Pointer to the expected object. Never nullptr. Call is invalid if this
|
||
|
|
* instance is in error state.
|
||
|
|
*/
|
||
|
|
ResultT* operator->()
|
||
|
|
{
|
||
|
|
assert(m_valid);
|
||
|
|
return &m_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Reference to the expected object. Behavior is undefined if this
|
||
|
|
* instance is in error state.
|
||
|
|
*/
|
||
|
|
ResultT& operator*() &
|
||
|
|
{
|
||
|
|
assert(m_valid);
|
||
|
|
return m_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
ResultT&& operator*() &&
|
||
|
|
{
|
||
|
|
assert(m_valid);
|
||
|
|
return std::move(m_result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Const reference to the expected object. Behavior is undefined if this
|
||
|
|
* instance is in error state.
|
||
|
|
*/
|
||
|
|
const ResultT& operator*() const &
|
||
|
|
{
|
||
|
|
assert(m_valid);
|
||
|
|
return m_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
const ResultT&& operator*() const &&
|
||
|
|
{
|
||
|
|
assert(m_valid);
|
||
|
|
return std::move(m_result);
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
ResultT m_result;
|
||
|
|
Error m_error;
|
||
|
|
bool m_valid{true};
|
||
|
|
};
|
||
|
|
|
||
|
|
} // namespace pymol
|
||
|
|
|
||
|
|
/**
|
||
|
|
* If `res` is in error state, return from the calling scope with `res.error()`.
|
||
|
|
* @param res Expression of type pymol::Result
|
||
|
|
* @note Inspired by `g_return_val_if_fail` from glib, except that the check
|
||
|
|
* will always be performed, there is nothing like `G_DISABLE_CHECKS`.
|
||
|
|
*/
|
||
|
|
#define p_return_if_error(res) \
|
||
|
|
{ \
|
||
|
|
auto&& _res_evaluated_ = res; \
|
||
|
|
if (!_res_evaluated_) \
|
||
|
|
return _res_evaluated_.error_move(); \
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Like p_return_if_error but add a prefix to the error message.
|
||
|
|
*/
|
||
|
|
#define p_return_if_error_prefixed(res, prefix) \
|
||
|
|
{ \
|
||
|
|
auto&& _res_evaluated_ = res; \
|
||
|
|
if (!_res_evaluated_) \
|
||
|
|
return pymol::make_error(prefix, _res_evaluated_.error().what()); \
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* If `expr` evaluates to false, return from the calling scope with `val`.
|
||
|
|
* @note Inspired by `g_return_val_if_fail` from glib, except that the check
|
||
|
|
* will always be performed, there is nothing like `G_DISABLE_CHECKS`.
|
||
|
|
*/
|
||
|
|
#define p_return_val_if_fail(expr, val) \
|
||
|
|
{ \
|
||
|
|
if (!(expr)) \
|
||
|
|
return val; \
|
||
|
|
}
|