/*
(c) 2004-14 Filip Stoklas, aka FipS, www.4FipS.com
THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE
*/
#ifndef FS_HEADER__fs_common_h__GUARD
#define FS_HEADER__fs_common_h__GUARD
#include "fs_config.h"
#include <string> // TODO: Get rid of this.
#include <exception> // TODO: Get rid of this.
/*
Usage:
- FS_ASSERT(cond && "Optional message...");
- FS_TRACE(("[x] File '%s' not found!\n", fname)); // [x], [!], [o], [.]
- FS_PROBE("x", 0.0);
Notes:
- {} scope is used to protect from the 'dangling else'.
- do-while is used to enforce a semicolon.
- The double-parentheses let the compiler always check for syntactic validity.
- (0,0) & volatile to suppress MSVC warning C4127.
- Custom handler setters and getters are not thread-safe (use carefully).
Links:
- http://stackoverflow.com/q/1644868
*/
#if defined(FS_PLATFORM_WIN)
# define FS_DEBUG_BREAK do { __debugbreak(); } while(0,0)
#elif defined(FS_PLATFORM_OSX)
# define FS_DEBUG_BREAK do { __asm__("int $3"); } while(0,0)
#else
# define FS_DEBUG_BREAK do { } while(0,0)
#endif
#define FS_UNUSED(x) do { (void)sizeof(x); } while(0,0)
// --- ASSERT ---
#if defined(FS_ENABLE_ASSERT)
# define FS_ASSERT(cond) \
do { \
const volatile bool result = (cond) ? true : false; \
if(!result && fs::assert::dispatch(#cond, __FUNCTION__, __FILE__, __LINE__)) \
{ FS_DEBUG_BREAK; } \
} while(0,0)
#else
# define FS_ASSERT(cond) do { FS_UNUSED(cond); } while(0,0)
#endif
#if defined(FS_ENABLE_ASSERT)
# define FS_VERIFY(cond) FS_ASSERT(cond)
#else
# define FS_VERIFY(cond) (void(cond))
#endif
namespace fs { namespace assert {
bool dispatch(const char *cond, const char *func, const char *file, int line) FS_NOEXCEPT;
using handler_type = bool (*)(const char *cond, const char *func, const char *file, int line);
handler_type set_handler(handler_type h) FS_NOEXCEPT;
handler_type handler() FS_NOEXCEPT;
bool default_handler(const char *cond, const char *func, const char *file, int line) FS_NOEXCEPT;
}} // namespace fs::asset
// --- TRACE ---
#if defined(FS_ENABLE_TRACE)
# define FS_TRACE(params) fs::trace::dispatch params
#else
# define FS_TRACE(params) do { if(0,0) fs::trace::dispatch params; } while(0,0)
#endif
namespace fs { namespace trace {
void dispatch(const char *fmt, ...) FS_NOEXCEPT;
using handler_type = void (*)(const char *text);
handler_type set_handler(handler_type h) FS_NOEXCEPT;
handler_type handler() FS_NOEXCEPT;
void default_handler(const char *text) FS_NOEXCEPT;
}} // namespace fs::trace
// --- PROBE ---
#if defined(FS_ENABLE_PROBE)
# define FS_PROBE(key, val) fs::probe::dispatch(key, val)
#else
# define FS_PROBE(key, val) do { if(0,0) fs::probe::dispatch(key, val); } while(0,0)
#endif
namespace fs { namespace probe {
void dispatch(const char *key, double val) FS_NOEXCEPT;
using handler_cb = void (*)(void *ctx, const char *key, double val);
struct handler_type { handler_cb cb; void *ctx; };
handler_type set_handler(handler_type h) FS_NOEXCEPT;
handler_type handler() FS_NOEXCEPT;
void default_handler(void *ctx, const char *key, double val) FS_NOEXCEPT;
}} // namespace fs::probe
// --- ERROR ---
#define FS_ERROR(err) \
do { \
if(fs::error::debug_break_enabled()) { FS_DEBUG_BREAK; } \
fs::error::dispatch(err); \
} while(0,0)
namespace fs { namespace error {
class error : public std::runtime_error
{
public:
error(const std::string &what) FS_NOEXCEPT : std::runtime_error(what) {}
};
void dispatch(const error &err) FS_NOEXCEPT;
using handler_type = void(*)(const error &err);
handler_type set_handler(handler_type h) FS_NOEXCEPT;
handler_type handler() FS_NOEXCEPT;
void default_handler(const error &err) FS_NOEXCEPT;
bool enable_debug_break(bool on) FS_NOEXCEPT;
bool debug_break_enabled() FS_NOEXCEPT;
class not_implemented : public error
{
public:
not_implemented() FS_NOEXCEPT : error("Not implemented!") {}
};
}} // namespace fs::error
namespace fs {
// --- NARROW CAST ---
template <typename T, typename F> // TO/FROM (unsigned/unsigned)
static typename std::enable_if<std::is_unsigned<T>::value && std::is_unsigned<F>::value, T>::type narrow_cast(F value) FS_NOEXCEPT
{
FS_ASSERT(value <= std::numeric_limits<T>::max());
return static_cast<T>(value);
}
template <typename T, typename F> // TO/FROM (signed/signed)
static typename std::enable_if<std::is_signed<T>::value && std::is_signed<F>::value, T>::type narrow_cast(F value) FS_NOEXCEPT
{
FS_ASSERT(value >= std::numeric_limits<T>::min() && value <= std::numeric_limits<T>::max());
return static_cast<T>(value);
}
template <typename T, typename F> // TO/FROM (unsigned/signed)
static typename std::enable_if<std::is_unsigned<T>::value && std::is_signed<F>::value, T>::type narrow_cast(F value) FS_NOEXCEPT
{
FS_ASSERT(value >= 0 && static_cast<typename std::make_unsigned<F>::type>(value) <= std::numeric_limits<T>::max());
return static_cast<T>(value);
}
template <typename T, typename F> // TO/FROM (signed/unsigned)
static typename std::enable_if<std::is_signed<T>::value && std::is_unsigned<F>::value, T>::type narrow_cast(F value) FS_NOEXCEPT
{
FS_ASSERT(value <= static_cast<typename std::make_unsigned<T>::type>(std::numeric_limits<T>::max()));
return static_cast<T>(value);
}
// --- MISC ---
double sys_time() FS_NOEXCEPT;
} // namespace fs
#endif // FS_HEADER__fs_common_h__GUARD