#pragma once #include <type_traits> #include <exception> #include <stddef.h> #include <utility> #include <stdio.h> #include "compat.hpp" #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 #if !SPRAWL_EXCEPTIONS_ENABLED # if defined(__GNUC__) # define SPRAWL_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) # elif defined _WIN32 # define SPRAWL_WARN_UNUSED_RESULT _Check_return_ # endif #else # define SPRAWL_WARN_UNUSED_RESULT #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_F(msg, ...) fprintf(stderr, msg, ## __VA_ARGS__); fputs("\n", stderr); fflush(stderr); std::terminate(); #define SPRAWL_ABORT_MSG(msg, ...) fputs(msg, stderr); 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)) namespace sprawl { #define SPRAWL_EXCEPTION(baseId, id, name, type) id, enum class 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<ExceptionId id> struct ExceptionBaseClass { }; template<> struct ExceptionBaseClass<ExceptionId::GENERAL_EXCEPTION> { typedef ExceptionBase base; }; template<ExceptionId error_code> class Exception; #define SPRAWL_EXCEPTION(baseId, id, name, type) \ template<> \ struct ExceptionBaseClass<ExceptionId::id> \ { \ typedef Exception<ExceptionId::baseId> base; \ }; #include "exceptions.hpp" #undef SPRAWL_EXCEPTION template<ExceptionId error_code> class Exception : public ExceptionBaseClass<error_code>::base { public: virtual char const* what() const throw () override { return ExceptionString(error_code); } ~Exception() throw () { } virtual ExceptionId GetId() const throw() override { return error_code; } }; typedef Exception<ExceptionId::GENERAL_EXCEPTION> GeneralException; #define SPRAWL_EXCEPTION(baseId, id, name, type) typedef Exception<ExceptionId::id> type; #include "exceptions.hpp" #undef SPRAWL_EXCEPTION } #if SPRAWL_EXCEPTIONS_ENABLED namespace sprawl { template<typename T> using ErrorState = T; } # define SPRAWL_THROW_EXCEPTION(exception) throw (exception) # define SPRAWL_RETHROW(expression) expression # define SPRAWL_RETHROW_OR_GET(expression, value) value = expression # define SPRAWL_ACTION_ON_ERROR(expression, action) try{ (expression); } catch(sprawl::ExceptionBase& e) { (action); } #else namespace sprawl { template<typename T> class ErrorState; class ErrorStateTypeDetector {}; } template<typename T> class sprawl::ErrorState : public ErrorStateTypeDetector { public: template<typename... Params> ErrorState(Params&&... params) : element() , error_code(ExceptionId::NONE) #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) , error_code_checked(false) #endif { new(&element) T(std::forward<Params>(params)...); } ErrorState() : element() , error_code(ExceptionId::NONE) #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) , error_code_checked(false) #endif { new(&element) T(); } ErrorState(ExceptionId rethrow_error_code) : element() , error_code(rethrow_error_code) #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) , error_code_checked(false) #endif { } template<sprawl::ExceptionId error_code_> ErrorState(Exception<error_code_> const&) : element() , error_code(error_code_) #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) , error_code_checked(false) #endif { } template<sprawl::ExceptionId error_code_> ErrorState(Exception<error_code_>&&) : element() , error_code(error_code_) #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) , error_code_checked(false) #endif { } #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) ~ErrorState() { if (error_code != ExceptionId::NONE && !error_code_checked) { fprintf(stderr, "ErrorState object destroyed with unhandled exception state!\n" "(To disable this check on debug builds, define SPRAWL_ERRORSTATE_PERMISSIVE; to enable on release builds, define SPRAWL_ERRORSTATE_STRICT)\n" "The error was: "); SPRAWL_ABORT_MSG(ErrorString()); } } #endif inline operator T&() { return Get(); } inline T& Get() { #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) if (error_code != ExceptionId::NONE) { SPRAWL_ABORT_MSG(sprawl::ExceptionString(error_code)); } #endif return reinterpret_cast<T&>(element); } bool Error() { return error_code != ExceptionId::NONE; } sprawl::ExceptionId ErrorCode() { #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) error_code_checked = true; #endif return error_code; } char const* ErrorString() { #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) error_code_checked = true; #endif return ExceptionString(error_code); } private: ErrorState(ErrorState const& other); ErrorState& operator=(ErrorState const& other); typename std::aligned_storage<sizeof(T), alignof(T)>::type element; sprawl::ExceptionId error_code; #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) bool error_code_checked; #endif }; template<typename T> class sprawl::ErrorState<T&> : public ErrorStateTypeDetector { public: ErrorState(T& elem) : element(&elem) , error_code(ExceptionId::NONE) #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) , error_code_checked(false) #endif { } template<sprawl::ExceptionId error_code_> ErrorState(Exception<error_code_> const&) : element() , error_code(error_code_) #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) , error_code_checked(false) #endif { } ErrorState(ExceptionId rethrow_error_code) : element() , error_code(rethrow_error_code) #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) , error_code_checked(false) #endif { } template<sprawl::ExceptionId error_code_> ErrorState(Exception<error_code_>&&) : element() , error_code(error_code_) #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) , error_code_checked(false) #endif { } #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) ~ErrorState() { if (error_code != ExceptionId::NONE && !error_code_checked) { fprintf(stderr, "ErrorState object destroyed with unhandled exception state!\n" "(To disable this check on debug builds, define SPRAWL_ERRORSTATE_PERMISSIVE; to enable on release builds, define SPRAWL_ERRORSTATE_STRICT)\n" "The error was: "); SPRAWL_ABORT_MSG(ErrorString()); } } #endif inline operator T&() { return Get(); } inline T& Get() { #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) if (error_code != ExceptionId::NONE) { SPRAWL_ABORT_MSG(sprawl::ExceptionString(error_code)); } #endif return *element; } bool Error() { return error_code != ExceptionId::NONE; } sprawl::ExceptionId ErrorCode() { #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) error_code_checked = true; #endif return error_code; } char const* ErrorString() { #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) error_code_checked = true; #endif return ExceptionString(error_code); } template<typename U> auto operator=(U&& value) -> decltype(std::declval<T>() = std::forward<U>(value)) { return *element = std::forward<T>(value); } private: ErrorState& operator=(ErrorState const& other); T* element; sprawl::ExceptionId error_code; #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) bool error_code_checked; #endif }; template<> class sprawl::ErrorState<void> : public ErrorStateTypeDetector { public: ErrorState() : error_code(ExceptionId::NONE) #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) , error_code_checked(false) #endif { } ErrorState(ExceptionId rethrow_error_code) : error_code(rethrow_error_code) #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) , error_code_checked(false) #endif { } template<sprawl::ExceptionId error_code_> ErrorState(Exception<error_code_> const&) : error_code(error_code_) #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) , error_code_checked(false) #endif { } #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) ~ErrorState() { if (error_code != ExceptionId::NONE && !error_code_checked) { fprintf(stderr, "ErrorState object destroyed with unhandled exception state!\n" "(To disable this check on debug builds, define SPRAWL_ERRORSTATE_PERMISSIVE; to enable on release builds, define SPRAWL_ERRORSTATE_STRICT)\n" "The error was: "); SPRAWL_ABORT_MSG(ErrorString()); } } #endif bool Error() { return error_code != ExceptionId::NONE; } sprawl::ExceptionId ErrorCode() { #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) error_code_checked = true; #endif return error_code; } char const* ErrorString() { #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) error_code_checked = true; #endif return ExceptionString(error_code); } private: ErrorState& operator=(ErrorState const& other); sprawl::ExceptionId error_code; #if (SPRAWL_DEBUG || defined(SPRAWL_ERRORSTATE_STRICT)) && !defined(SPRAWL_ERRORSTATE_PERMISSIVE) bool error_code_checked; #endif }; # define SPRAWL_THROW_EXCEPTION(exception) return exception; # define SPRAWL_RETHROW(expression) auto SPRAWL_CONCAT(error__, __LINE__) = (expression); if(SPRAWL_CONCAT(error__, __LINE__).Error()) { return SPRAWL_CONCAT(error__, __LINE__).ErrorCode(); } # define SPRAWL_RETHROW_OR_GET(expression, value) auto SPRAWL_CONCAT(error__, __LINE__) = (expression); if(SPRAWL_CONCAT(error__, __LINE__).Error()) { return SPRAWL_CONCAT(error__, __LINE__).ErrorCode(); } value = SPRAWL_CONCAT(error__, __LINE__).Get() # define SPRAWL_ACTION_ON_ERROR(expression, action) auto SPRAWL_CONCAT(error__, __LINE__) = (expression); if(SPRAWL_CONCAT(error__, __LINE__).Error()) { action; } #endif
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#7 | 19912 | ShadauxCat |
Fix various linux warnings and errors under clang 3.6 #review-19913 |
||
#6 | 19906 | ShadauxCat |
- Added tag, compile time string type - Since tag requires visual studio 2015, removed compatibility code for earlier versions of visual studio - Improved compiler detection - Added endianness detection - Added template if/else helper - Fixed bug with murmur3 64 bit - Added seed argument for murmur3 #review-19907 |
||
#5 | 16768 | ShadauxCat |
Improvements to error handling in builds with exceptions disabled: - In debug builds or with SPRAWL_ERRORSTATE_STRICT enabled, ErrorState will output a message to stderr and terminate if Get() is called when an error flag is set. (In release buils or with SPRAWL_ERRORSTATE_PERMISSIVE defined, Get() will return junk memory in this case.) - In debug builds or with SPRAWL_ERRORSTATE_STRICT enabled, ErrorState will output a message to stderr and terminate if its destructor is called without checking the errorstate if an error is present (equivalent to an exception terminating the application if no catch() block is present for it). - On linux builds and when running "Analyze" through visual studio, a warning will be issued if any function returning ErrorState has its return value ignored. (This only applies to builds with exceptions not enabled; when exceptions are enabled no warning is issued) - Many functions that could return ErrorState were having their return values silently ignored in internal sprawl code so the user would not find out about errors if exceptions are disabled; now anything in sprawl code that calls a function returning ErrorState will either handle the error, or (in most cases) surface it back up to the user. - As a positive side-effect of the warnings for ignoring ErrorState, several constructors that were capable of throwing exceptions are no longer capable of doing so. #review-16769 |
||
#4 | 16380 | ShadauxCat |
Missed a header, also corrected missing newline in exceptions.hpp, also corrected exceptions.hpp being exceptions.h. #review-16381 |
||
#3 | 16378 | ShadauxCat |
New exception framework, phase one. Added new class, ErrorState, for handling errors when exceptions are disabled. When exceptions are enabled, ErrorState<T> is an alias for T. When they're disabled, ErrorState<T> additionally encodes an error code, and will have junk data (and probably a crash) if an error is returned and not checked before the data is used. ErrorState<T> is implicitly convertible to and from T, so applications that don't care about errors can code like they don't exist... Phase two will involve overloading operators on ErrorState so that things that return ErrorState can still function as much as possible like they do when exceptions are enabled. #review-16379 |
||
#2 | 16171 | ShadauxCat |
- Created type traits header including macros to make checks for types having any operator or member function, and seeded it with every operator operating on the same type. For function and/or type combinations not already handled, creating a new type traits struct is just a single line of code. - Updated coroutine to use the new type traits header and removed the explicit operator() check - Added alternative to SPRAWL_THROW_EXCEPTION - SPRAWL_THROW_EXCEPTION_OR_ABORT, which as it sounds, will either throw the exception if exceptions are enabled, otherwise will print the message and abort. This is for cases where returning a value reliably isn't possible, such as in constructors or code that returns a template type that may not be default constructible. - Added a layer of safety around coroutines; trying to call the various functions that pause the current coroutine will now throw an exception (if enabled) or abort (if not) if you try to call the wrong pause function (i.e., calling an empty yield() on a coroutine that's supposed to return a value) - Added ability to determine what type a CoroutineBase object actually is underneath - Added function in logging to flush one specific category instead of flushing everything #review-16172 |
||
#1 | 11496 | ShadauxCat | Initial checkin: Current states for csbuild and libSprawl |