elBase.h
/********************************************************************************
* Elgrint base header
* Elgrint library, version 1.0
* Created by Dimitry Rotstein
* Copyright(C) 2013 by Miranor
* Description:
* - Defines atomic/elementary types, constants, global functions, and macros
* for general use in all Elgrint modules
*
*******************************************************************************/
#ifndef MIRANOR_ELGRINT_BASE
#define MIRANOR_ELGRINT_BASE
#include <limits.h> // Helps determine IntN and UIntN
#include <math.h> // Often useful
#include <time.h> // 'clock' is used often
#ifdef _VCPP_COMPILER
#pragma warning(disable : 4355) // Allow 'this' in init lists (used extensively)
#endif
namespace Elgrint
{
/////////////////////////////////////////////////////////////////////////////////
/////////////////////// Atomic types (8/16/32/64 bits) //////////////////////////
/////////////////////////////////////////////////////////////////////////////////
// Define Int8/UInt8
#if UCHAR_MAX == 0xFF
typedef signed char Int8;
typedef unsigned char UInt8;
#else
#error Unable to identify an 8-bit type
#endif
// Define Int16/UInt16
#if USHRT_MAX == 0xFFFF
typedef signed short Int16;
typedef unsigned short UInt16;
#elif UINT_MAX == 0xFFFF
typedef signed int Int16;
typedef unsigned int UInt16;
#elif ULONG_MAX == 0xFFFF
typedef signed long Int16;
typedef unsigned long UInt16;
#else
#error Unable to identify a 16-bit type
#endif
// Define Int32/UInt32
#if USHRT_MAX == 0xFFFFFFFF
typedef signed short Int32;
typedef unsigned short UInt32;
#elif UINT_MAX == 0xFFFFFFFF
typedef signed int Int32;
typedef unsigned int UInt32;
#elif ULONG_MAX == 0xFFFFFFFF
typedef signed long Int32;
typedef unsigned long UInt32;
#else
#error Unable to identify a 32-bit type
#endif
// Define Int64/UInt64
#if UINT_MAX == 0xFFFFFFFFFFFFFFFF
typedef signed int Int64;
typedef unsigned int UInt64;
#elif ULONG_MAX == 0xFFFFFFFFFFFFFFFF
typedef signed long Int64;
typedef unsigned long UInt64;
#else
typedef signed long long Int64;
typedef unsigned long long UInt64;
#endif
/////////////////////////////////////////////////////////////////////////////////
//////////////////////// Elementary types (atomic-based) ////////////////////////
/////////////////////////////////////////////////////////////////////////////////
// MNum: large enough to enumerate all addressable memory
#if defined _WIN64
typedef UInt64 MNum;
#elif defined _WIN32
typedef UInt32 MNum;
#else
typedef UInt64 MNum;
#endif
typedef UInt64 MFileSize; // For MFile (MNum may not be large enough)
typedef UInt32 MLocusElem; // For MLocus (external for simplicity)
typedef double MSizeElem; // For MSize/MRect (external for simplicity)
typedef double MPointElem; // For MPoint/MRect (external for simplicity)
/////////////////////////////////////////////////////////////////////////////////
///////////////////////////// Elementary constants //////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
const UInt32 None = 0x7FFF7F7F;
const UInt32 Auto = 0x7FFF7F7E;
const UInt32 Same = 0x7FFF7F7D;
const UInt32 Zero = 0;
const MNum MaxNum = MNum(-1);
const MNum MaxNoticeID = UInt32(-1);
const MNum MaxTimerID = 2000000000;
const MNum MinTimerDelay = 10;
const MNum MaxTimerDelay = 2000000000; // ~23.1 days
const MFileSize MaxFileSize = MFileSize(-1);
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// Functions ///////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
// The 'IsValid' function detects invalid values: None/Auto/Same, and
// derived (e.g. NoneRect). Can also be used in other cases, e.g. for MWindow
// Note: IsValid(float) is defined below because it uses M_PARAM_CHECK
//
inline bool IsValid(const Int8& n) { return (n&0xF0) != 0x70; }
inline bool IsValid(const UInt8& n) { return (n&0xF0) != 0x70; }
inline bool IsValid(const Int16& n) { return (n&0xFFF0) != 0x7F70; }
inline bool IsValid(const UInt16& n) { return (n&0xFFF0) != 0x7F70; }
inline bool IsValid(const Int32& n) { return (n&0xFFFFFFF0) != 0x7FFF7F70; }
inline bool IsValid(const UInt32& n) { return (n&0xFFFFFFF0) != 0x7FFF7F70; }
inline bool IsValid(const Int64& n) { return (n&0x00FFFFFFF0) != 0x007FFF7F70; }
inline bool IsValid(const UInt64& n) { return (n&0x00FFFFFFF0) != 0x007FFF7F70; }
inline bool IsValid(const double& n) { return n<0x007FFF7F70 || n>0x007FFF7F7F; }
inline bool IsValid(const long double& n) { return n<0x007FFF7F70 || n>0x007FFF7F7F; }
inline bool IsValid(const char& ch) { return ch >= 1 && ch <= 127; }
// The 'IsPlainType' functions allow MVector and MFile to operate noticeably
// faster, yet safely, for any type T, which satisfies all of the following
// conditions:
// - Does not allocate memory
// - Does not contain pointers/references (directly or indirectly)
// - Assignment operator can handle any garbage value
// - Has empty d-tor or no d-tor at all (i.e. d-tor can be skipped without problems)
// - Does not use "this" pointer explicitly, or doesn't have one at all
//
// All types are assumed to be non-plain for safety reasons, unless explicitly
// specified otherwise, by a specialization of IsPlainType function, as done for
// all built-in types below. You can define additional IsPlainType specializations
// for any type which satisfies the above conditions. If you're not sure that
// it does, then do NOT redefine IsPlainType
template <class T> inline bool IsPlainType() { return false; } // Universal version
template<> inline bool IsPlainType<signed char> () { return true; }
template<> inline bool IsPlainType<unsigned char> () { return true; }
template<> inline bool IsPlainType<signed short> () { return true; }
template<> inline bool IsPlainType<unsigned short> () { return true; }
template<> inline bool IsPlainType<signed int> () { return true; }
template<> inline bool IsPlainType<unsigned int> () { return true; }
template<> inline bool IsPlainType<signed long> () { return true; }
template<> inline bool IsPlainType<unsigned long> () { return true; }
template<> inline bool IsPlainType<signed long long> () { return true; }
template<> inline bool IsPlainType<unsigned long long>() { return true; }
template<> inline bool IsPlainType<float> () { return true; }
template<> inline bool IsPlainType<double> () { return true; }
template<> inline bool IsPlainType<long double> () { return true; }
template<> inline bool IsPlainType<bool> () { return true; }
template<> inline bool IsPlainType<char> () { return true; }
// Max/Min returns a reference to the largest/smallest value of the two
template <class T>
inline const T& Max(const T& a, const T& b) { return b<a?a:b; }
template <class T>
inline const T& Min(const T& a, const T& b) { return a<b?a:b; }
// If 'val' is out of ['minVal','maxVal'] range, return the closest value 'val'
// within this range. If 'minVal' > 'maxVal', returns 'maxVal' for any 'val'
//
template <class T>
inline const T& ToRange(const T& val, const T& minVal, const T& maxVal)
{
return Min(Max(val,minVal),maxVal);
}
// Swaps two values (specialized for collections using their 'swapWith' methods)
//
template <class T>
inline void Swap(T& a, T& b) { T tmp = a; a = b; b = tmp; }
// Returns true iff bit number 'b' in 'src' is set
//
template <class N>
inline bool IsBit(const N& src, UInt8 b)
{
return b < sizeof(N)*8 && (src & (N(1)<<b)) != 0;
}
// Extracts bit sequence from bit number 'b1' through 'b2' and returns the integer
// value of a number composed of the extracted bits.
//
template <class N>
inline N GetBits(N src, UInt8 b1, UInt8 b2)
{
const UInt8 LAST_BIT = sizeof(N)*8 - 1;
b2 = Min(b2, LAST_BIT);
if (b1 > b2) return 0;
src <<= (LAST_BIT-b2);
src >>= (LAST_BIT-b2+b1);
return src;
}
/////////////////////////////////////////////////////////////////////////////////
////////////////////////////// Assertion macros /////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
//
// M_ASSERT - standard assertion for internal consistency checks
// M_PARAM_CHECK - similar to M_ASSERT, but generates a more user-friendly output
// on assertion failure. Used on arguments of public functions
extern bool assertRaised; // Prevents stack overflow due to assertion within assertion
// Must be defined in RELEASE mode as well, because it's used in the 'catch' statements
struct _MAssertionRecord
{
const char* condStr;
const char* filename;
int lineNum;
_MAssertionRecord(const char* acondStr, const char* afilename, int alineNum) :
condStr(acondStr), filename(afilename), lineNum(alineNum)
{}
};
#ifdef _DEBUG
#define M_PARAM_CHECK(cond,msg) \
{ if (!(cond) && !assertRaised) \
{ assertRaised = true; throw _MAssertionRecord(msg, __FILE__, __LINE__); } \
}
#define M_ASSERT(cond) \
{ if (!(cond) && !assertRaised) \
{ assertRaised = true; throw _MAssertionRecord(#cond, __FILE__, __LINE__); } \
}
#else
#define M_PARAM_CHECK(cond,msg)
#define M_ASSERT(cond)
#endif
...