mirror of
https://github.com/dankamongmen/notcurses.git
synced 2024-11-02 09:40:15 +00:00
64eeb95f1e
Nick prefers error handling based on exceptions in all cases, while I prefer to save exception handling for truly exceptional situations - function parameter validation and class constructor. However, there's no need to not support both approaches, to be chosen at the discretion of the developer. NCPP follows RAII and all classes throw exceptions from their constructors in case they cannot initialize properly. Likewise, functions taking pointers that are required validate them and throw exceptions whenever the requirement isn't met. This commit goes one step further in that it enables optional validation of notcurses function return values and throwing an exception (`ncpp::call_error`) should the function signal an error. This is disabled by default but it can be enabled by defining the `NCPP_EXCEPTIONS_PLEASE` macro (preferably on the command line or before *each* inclusion of any NCPP headers). Out of necessity, this breaks the ABI (plus I found a handful of minor issues in the code), but I think it's worth having this support in place.
90 lines
2.2 KiB
C++
90 lines
2.2 KiB
C++
#ifndef __NCPP_ROOT_HH
|
|
#define __NCPP_ROOT_HH
|
|
|
|
#include <type_traits>
|
|
#include <string>
|
|
#include <notcurses/notcurses.h>
|
|
|
|
#include "_helpers.hh"
|
|
#include "_exceptions.hh"
|
|
|
|
namespace ncpp {
|
|
#if defined (NCPP_EXCEPTIONS_PLEASE)
|
|
#define NOEXCEPT_MAYBE
|
|
#else
|
|
#define NOEXCEPT_MAYBE noexcept
|
|
#endif
|
|
|
|
class NCPP_API_EXPORT Root
|
|
{
|
|
protected:
|
|
static constexpr char ncpp_invalid_state_message[] = "notcurses++ is in an invalid state (already stopped?)";
|
|
|
|
protected:
|
|
template<typename TRet = bool, typename TValue = int>
|
|
TRet error_guard (TValue ret, TValue error_value) const
|
|
{
|
|
static constexpr bool ret_is_bool = std::is_same_v<TRet, bool>;
|
|
|
|
if constexpr (!ret_is_bool) {
|
|
static_assert (std::is_same_v<TRet, TValue>, "Both TRet and TValue must be the same type unless TValue is 'bool'");
|
|
}
|
|
|
|
if (ret != error_value) {
|
|
if constexpr (ret_is_bool) {
|
|
return true;
|
|
} else {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
#if defined (NCPP_EXCEPTIONS_PLEASE)
|
|
throw call_error ("Call returned an error value");
|
|
#else
|
|
if constexpr (ret_is_bool) {
|
|
return false;
|
|
} else {
|
|
return ret;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
template<typename TRet = bool, typename TValue = int>
|
|
TRet error_guard_cond ([[maybe_unused]] TValue ret, bool error_value) const
|
|
{
|
|
static constexpr bool ret_is_bool = std::is_same_v<TRet, bool>;
|
|
|
|
if constexpr (!ret_is_bool) {
|
|
static_assert (std::is_same_v<TRet, TValue>, "Both TRet and TValue must be the same type unless TValue is 'bool'");
|
|
}
|
|
|
|
if (!error_value) {
|
|
if constexpr (ret_is_bool) {
|
|
return true;
|
|
} else {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
#if defined (NCPP_EXCEPTIONS_PLEASE)
|
|
throw call_error ("Call returned an error value");
|
|
#else
|
|
if constexpr (ret_is_bool) {
|
|
return false;
|
|
} else {
|
|
return ret;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
notcurses* get_notcurses () const;
|
|
|
|
// All the objects which need to destroy notcurses entities (planes, panelreel etc etc) **have to** call this
|
|
// function before calling to notcurses from their destructor. This is to prevent a segfault when
|
|
// NotCurses::stop has been called and the app uses smart pointers holding NotCurses objects which may be
|
|
// destructed **after** notcurses is stopped.
|
|
bool is_notcurses_stopped () const noexcept;
|
|
};
|
|
}
|
|
#endif
|