#pragma once #include #include #if defined(SPRAWL_NO_EXCEPTIONS) # define SPRAWL_EXCEPTIONS_ENABLED 0 #elif defined(__clang__) # define SPRAWL_EXCEPTIONS_ENABLED __has_feature(cxx_exceptions) #elif defined(__GNUC__) # ifdef __EXCEPTIONS # define SPRAWL_EXCEPTIONS_ENABLED 1 # else # define SPRAWL_EXCEPTIONS_ENABLED 0 # endif #elif defined(_WIN32) # ifdef _CPPUNWIND # define SPRAWL_EXCEPTIONS_ENABLED 1 # else # define SPRAWL_EXCEPTIONS_ENABLED 0 # endif #else # define SPRAWL_EXCEPTIONS_ENABLED 0 #endif namespace sprawl { #define SPRAWL_EXCEPTION(baseId, id, name, type) id, enum ExceptionId { NONE, GENERAL_EXCEPTION, #include "exceptions.hpp" }; #undef SPRAWL_EXCEPTION class ExceptionBase : public std::exception { public: ~ExceptionBase() throw() { } virtual ExceptionId GetId() const throw() = 0; }; inline char const* ExceptionString(ExceptionId id) { #define SPRAWL_EXCEPTION(baseId, id, name, type) name, static char const* const exception_table[] = { "", "Unknown or unspecified error", #include "exceptions.hpp" }; #undef SPRAWL_EXCEPTION return exception_table[size_t(id)]; } template struct ExceptionBaseClass { }; template<> struct ExceptionBaseClass { typedef ExceptionBase base; }; template class Exception; #define SPRAWL_EXCEPTION(baseId, id, name, type) \ template<> \ struct ExceptionBaseClass \ { \ typedef Exception base; \ }; #include "exceptions.hpp" #undef SPRAWL_EXCEPTION template class Exception : public ExceptionBaseClass::base { public: char const* what() const throw () { return ExceptionString(error_code); } ~Exception() throw () { } virtual ExceptionId GetId() const throw() override { return error_code; } }; typedef Exception GeneralException; #define SPRAWL_EXCEPTION(baseId, id, name, type) typedef Exception type; #include "exceptions.hpp" #undef SPRAWL_EXCEPTION } #if SPRAWL_EXCEPTIONS_ENABLED namespace sprawl { template using ErrorState = T; } # define SPRAWL_THROW_EXCEPTION(exception) throw exception #else namespace sprawl { template class ErrorState; } #if (defined(_WIN32) && _MSC_VER < 1900 && !defined(alignof)) # define alignof __alignof # define SPRAWL_DEFINED_ALIGNOF #endif template class sprawl::ErrorState { public: template ErrorState(Params&&... params) : element() , error_code(ExceptionId::NONE) { new(&element) T(std::forward(params)...); } ErrorState() : element() , error_code(ExceptionId::NONE) { new(&element) T(); } template ErrorState(Exception const& e) : element() , error_code(error_code_) { } template ErrorState(Exception&& e) : element() , error_code(error_code_) { } operator T() { return reinterpret_cast(element); } T& Get() { return reinterpret_cast(element); } bool Error() { return error_code != ExceptionId::NONE; } sprawl::ExceptionId ErrorCode() { return error_code; } char const* ErrorString() { return ExceptionString(error_code); } private: ErrorState(ErrorState const& other); ErrorState& operator=(ErrorState const& other); typename std::aligned_storage::type element; sprawl::ExceptionId error_code; }; template class sprawl::ErrorState { public: ErrorState(T& elem) : element(&elem) , error_code(ExceptionId::NONE) { } template ErrorState(Exception const& e) : element() , error_code(error_code_) { } template ErrorState(Exception&& e) : element() , error_code(error_code_) { } operator T&() { return *element; } T& Get() { return *element; } bool Error() { return error_code != ExceptionId::NONE; } sprawl::ExceptionId ErrorCode() { return error_code; } char const* ErrorString() { return ExceptionString(error_code); } template auto operator=(T&& value) -> decltype(*element = std::forward(value)) { return *element = std::forward(value); } private: ErrorState& operator=(ErrorState const& other); T* element; sprawl::ExceptionId error_code; }; template<> class sprawl::ErrorState { public: ErrorState() : error_code(ExceptionId::NONE) { } template ErrorState(Exception const& e) : error_code(error_code_) { } bool Error() { return error_code != ExceptionId::NONE; } sprawl::ExceptionId ErrorCode() { return error_code; } char const* ErrorString() { return ExceptionString(error_code); } private: ErrorState& operator=(ErrorState const& other); sprawl::ExceptionId error_code; }; #ifdef SPRAWL_DEFINED_ALIGNOF # undef alignof # undef SPRAWL_DEFINED_ALIGNOF #endif # define SPRAWL_THROW_EXCEPTION(exception) return exception; #endif #if SPRAWL_EXCEPTIONS_ENABLED # define SPRAWL_THROW_EXCEPTION_OR_ABORT(exception) throw exception #else # define SPRAWL_THROW_EXCEPTION_OR_ABORT(exception) fprintf(stderr, exception.what()); fflush(stderr); std::terminate() #endif #define SPRAWL_ABORT_MSG(msg, ...) fprintf(stderr, msg, ## __VA_ARGS__); fputs("\n", stderr); fflush(stderr); std::terminate(); #define SPRAWL_UNIMPLEMENTED_BASE_CLASS_METHOD SPRAWL_THROW_EXCEPTION(sprawl::UnimplementedVirtualMethod()) #define SPRAWL_UNIMPLEMENTED_BASE_CLASS_METHOD_ABORT SPRAWL_ABORT_MSG(sprawl::ExceptionString(sprawl::ExceptionId::UNIMPLEMENTED_VIRTUAL_METHOD))