Merge default into floating-point

floating-point
Nicolas Hake 2010-07-08 03:47:39 +02:00
commit 77b9c47cf8
24 changed files with 9989 additions and 9381 deletions

View File

@ -73,6 +73,7 @@ if(HAVE_NULLPTR)
CHECK_CXX_SOURCE_COMPILES("#include <cstddef>
template<class T> void f(T &&); template<> void f(std::nullptr_t &&) {} int main() { f(NULL); }" NULL_IS_NULLPTR_T)
endif()
CHECK_CXX_SOURCE_COMPILES("int main() { static_assert(true, \"\"); }" HAVE_STATIC_ASSERT)
if(MSVC_VERSION GREATER 1499)
# Activate minimal rebuild
@ -348,6 +349,11 @@ set(OC_CLONK_SOURCES
src/lib/C4Random.h
src/lib/C4Real.cpp
src/lib/C4Real.h
src/lib/C4RealImpl_Fixed.cpp
src/lib/C4RealImpl_Fixed.h
src/lib/C4RealImpl_FPU.h
src/lib/C4RealImpl_SSE.cpp
src/lib/C4RealImpl_SSE.h
src/lib/C4Rect.cpp
src/lib/C4Rect.h
src/lib/C4RTF.cpp

View File

@ -99,6 +99,11 @@ src/lib/C4Random.cpp \
src/lib/C4Random.h \
src/lib/C4Real.cpp \
src/lib/C4Real.h \
src/lib/C4RealImpl_Fixed.cpp \
src/lib/C4RealImpl_Fixed.h \
src/lib/C4RealImpl_FPU.h \
src/lib/C4RealImpl_SSE.cpp \
src/lib/C4RealImpl_SSE.h \
src/lib/C4Rect.cpp \
src/lib/C4Rect.h \
src/lib/C4RTF.cpp \

View File

@ -191,3 +191,6 @@
/* Define to 1 if your NULL is an instance of std::nullptr_t. */
#cmakedefine NULL_IS_NULLPTR_T 1
/* Define to 1 if your compiler supports static_assert */
#cmakedefine HAVE_STATIC_ASSERT 1

View File

@ -82,6 +82,7 @@ C4Application::~C4Application()
bool C4Application::DoInit()
{
assert(AppState == C4AS_None);
// Config overwrite by parameter
StdStrBuf sConfigFilename;
char szParameter[_MAX_PATH+1];
@ -120,6 +121,27 @@ bool C4Application::DoInit()
// Open log
OpenLog();
// Check for SSE support
bool has_sse = false;
struct registers
{
int eax, ebx, ecx, edx;
} regs = {0};
const uint32_t CPUID_EDX_HAS_SSE_FLAG = 1 << 25;
#if defined _MSC_VER
__cpuid(reinterpret_cast<int*>(&regs), 1);
#elif defined __GNUC__
__asm__ __volatile__("cpuid":"=d"(regs.edx):"a"(1):"%ebx","%ecx");
#endif
has_sse = (regs.edx & CPUID_EDX_HAS_SSE_FLAG) != 0;
if (!has_sse)
{
const char *message = "Your CPU does not support the SSE instruction set that is required by this program.";
Log(message);
MessageDialog(message);
return false;
}
Revision.Ref(OC_HG_REVISION);
// init system group

View File

@ -328,6 +328,17 @@ void C4PXSSystem::Cast(int32_t mat, int32_t num, int32_t tx, int32_t ty, int32_t
itofix(Random(level+1)-level)/10);
}
#include <boost/static_assert.hpp>
namespace
{
struct C4PXSSystem_Chunk
{
int32_t mat;
float x,y,xdir,ydir;
};
BOOST_STATIC_ASSERT(sizeof(C4PXSSystem_Chunk) == 4 + 4*4);
}
bool C4PXSSystem::Save(C4Group &hGroup)
{
unsigned int cnt;
@ -349,17 +360,23 @@ bool C4PXSSystem::Save(C4Group &hGroup)
CStdFile hTempFile;
if (!hTempFile.Create(Config.AtTempPath(C4CFN_TempPXS)))
return false;
#ifdef C4REAL_USE_FIXNUM
int32_t iNumFormat = 1;
#else
int32_t iNumFormat = 2;
#endif
if (!hTempFile.Write(&iNumFormat, sizeof (iNumFormat)))
return false;
for (cnt=0; cnt<PXSMaxChunk; cnt++)
if (Chunk[cnt]) // must save all chunks in order to keep order consistent on all clients
if (!hTempFile.Write(Chunk[cnt],PXSChunkSize * sizeof(C4PXS)))
{
// Serialize chunk
C4PXSSystem_Chunk serialize_buffer[PXSChunkSize];
for (size_t chunk_idx = 0; chunk_idx < PXSChunkSize; ++chunk_idx)
{
serialize_buffer[chunk_idx].mat = Chunk[cnt][chunk_idx].Mat;
serialize_buffer[chunk_idx].x = Chunk[cnt][chunk_idx].x;
serialize_buffer[chunk_idx].y = Chunk[cnt][chunk_idx].y;
serialize_buffer[chunk_idx].xdir = Chunk[cnt][chunk_idx].xdir;
serialize_buffer[chunk_idx].ydir = Chunk[cnt][chunk_idx].ydir;
}
if (!hTempFile.Write(&serialize_buffer, sizeof(serialize_buffer)))
return false;
}
if (!hTempFile.Close())
return false;
@ -380,36 +397,29 @@ bool C4PXSSystem::Load(C4Group &hGroup)
if (!hGroup.AccessEntry(C4CFN_PXS,&iBinSize)) return false;
// clear previous
Clear();
// using C4Real or float?
int32_t iNumForm = 1;
if (iBinSize % iChunkSize == 4)
{
if (!hGroup.Read(&iNumForm, sizeof (iNumForm))) return false;
if (!Inside<int32_t>(iNumForm, 1, 2)) return false;
iBinSize -= 4;
}
// old pxs-files have no tag for the number format
else if (iBinSize % iChunkSize != 0) return false;
// calc chunk count
iChunkNum = iBinSize / iChunkSize;
if (iChunkNum > PXSMaxChunk) return false;
for (uint32_t cnt=0; cnt<iChunkNum; cnt++)
{
if (!(Chunk[cnt]=new C4PXS[PXSChunkSize])) return false;
if (!hGroup.Read(Chunk[cnt],iChunkSize)) return false;
Chunk[cnt] = new C4PXS[PXSChunkSize];
// De-serialize chunk
C4PXSSystem_Chunk serialize_buffer[PXSChunkSize];
if (!hGroup.Read(&serialize_buffer, sizeof(serialize_buffer))) return false;
for (size_t chunk_idx = 0; chunk_idx < PXSChunkSize; ++chunk_idx)
{
Chunk[cnt][chunk_idx].Mat = serialize_buffer[chunk_idx].mat;
Chunk[cnt][chunk_idx].x = serialize_buffer[chunk_idx].x;
Chunk[cnt][chunk_idx].y = serialize_buffer[chunk_idx].y;
Chunk[cnt][chunk_idx].xdir = serialize_buffer[chunk_idx].xdir;
Chunk[cnt][chunk_idx].ydir = serialize_buffer[chunk_idx].ydir;
}
// count the PXS, Peter!
// convert num format, if neccessary
C4PXS *pxp; iChunkPXS[cnt]=0;
for (cnt2=0,pxp=Chunk[cnt]; cnt2<PXSChunkSize; cnt2++,pxp++)
if (pxp->Mat != MNone)
{
++iChunkPXS[cnt];
// convert number format
#ifdef C4REAL_USE_FIXNUM
if (iNumForm == 2) { FLOAT_TO_FIXED(&pxp->x); FLOAT_TO_FIXED(&pxp->y); FLOAT_TO_FIXED(&pxp->xdir); FLOAT_TO_FIXED(&pxp->ydir); }
#else
if (iNumForm == 1) { FIXED_TO_FLOAT(&pxp->x); FIXED_TO_FLOAT(&pxp->y); FIXED_TO_FLOAT(&pxp->xdir); FIXED_TO_FLOAT(&pxp->ydir); }
#endif
}
}
return true;

View File

@ -1535,7 +1535,7 @@ bool C4Command::InitEvaluation()
case C4CMD_MoveTo:
{
// Target coordinates by Target
if (Target) { Tx+=Target->GetX(); Ty+=Target->GetY(); Target=NULL; }
if (Target) { Tx+=C4VInt(Target->GetX()); Ty+=Target->GetY(); Target=NULL; }
// Adjust coordinates
int32_t iTx = Tx._getInt();
if (~Data.getInt() & C4CMD_MoveTo_NoPosAdjust) AdjustMoveToTarget(iTx,Ty,FreeMoveTo(cObj),cObj->Shape.Hgt);

View File

@ -3528,6 +3528,7 @@ public:
virtual void Byte(uint8_t &rByte) { if (haveCompleteMatch()) if (!iEntryNr--) { int32_t i=rByte; ProcessInt(i); rByte =i; } }
virtual void Boolean(bool &rBool) { if (haveCompleteMatch()) if (!iEntryNr--) ProcessBool(rBool); }
virtual void Character(char &rChar) { if (haveCompleteMatch()) if (!iEntryNr--) ProcessChar(rChar); }
virtual void Float(float &flt) { assert(!"Can't compile/decompile float from structure"); }
// The C4ID-Adaptor will set RCT_ID for it's strings (see C4Id.h), so we don't have to guess the type.
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType)

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@
* Copyright (c) 2002, 2005 Sven Eberhardt
* Copyright (c) 2002, 2004-2005, 2007 Peter Wortmann
* Copyright (c) 2005, 2007 Günther Brammer
* Copyright (c) 2010 Nicolas Hake
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
*
* Portions might be copyrighted by other authors who have contributed
@ -28,7 +29,7 @@
because floating point calculations are not guaranteed to be network
safe...however, it can be solved as a data type with operator
overloading, automatic type conversions, etc now - Sven2 */
/* After some time with synchronous float use, C4Fixed is used again to
/* After some time with synchronous float use, C4Real is used again to
work around the problem that different compilers produce different
floating point code, leading to desyncs between linux and windows
engines. */
@ -36,308 +37,159 @@
#ifndef INC_C4Real
#define INC_C4Real
#include <math.h>
// C4RealBase modes:
// C4REAL_MODE_SOFTWARE: fixpoint math, all operations emulated by
// software
// C4REAL_MODE_SOFT_FLOAT: floating-point math, all operations emulated by
// software
// C4REAL_MODE_FPU_FLOAT: floating-point math, all operations run on FPU
// C4REAL_MODE_SSE_FLOAT: floating-point math, all operations run on SSE
// unit (which is usually the FPU as well, but w/o
// extended precision)
#define C4REAL_MODE_SOFTWARE 1
//#define C4REAL_MODE_SOFT_FLOAT 2
#define C4REAL_MODE_FPU_FLOAT 3
#define C4REAL_MODE_SSE_FLOAT 4
// activate to switch to classic fixed-point math
#define C4REAL_USE_FIXNUM 1
#define inline ALWAYS_INLINE
#define FIXED_EMULATE_64BIT
// note: C4Fixed has to be defined even though it isn't used
// any more. It is used to convert old-format fixed values
// to the new-format float ones.
#ifdef C4REAL_USE_FIXNUM
extern long SineTable[9001]; // external table of sine values
#ifndef C4REAL_MODE
#define C4REAL_MODE C4REAL_MODE_SSE_FLOAT
#endif
// fixpoint shift (check 64 bit emulation before changing!)
#define FIXED_SHIFT 16
// fixpoint factor
#define FIXED_FPF int32_t(1 << FIXED_SHIFT)
#include <boost/type_traits/is_class.hpp>
#include <boost/type_traits/is_pod.hpp>
class C4Fixed
template<class C4RealImpl>
class C4RealBase
{
#ifdef C4REAL_USE_FIXNUM
friend int fixtoi(const C4Fixed &x);
friend int fixtoi(const C4Fixed &x, int32_t prec);
friend C4Fixed itofix(int32_t x);
friend C4Fixed itofix(int32_t x, int32_t prec);
friend float fixtof(const C4Fixed &x);
friend C4Fixed ftofix(float x);
#else
friend void FIXED_TO_FLOAT(float *pVal);
#endif
friend void CompileFunc(C4Fixed &rValue, StdCompiler *pComp);
C4RealImpl value;
friend C4RealBase Sin(const C4RealBase &);
friend C4RealBase Cos(const C4RealBase &);
public:
int32_t val; // internal value
inline C4RealBase(int32_t val = 0) : value(val) { }
inline C4RealBase(float val) : value(val) {}
inline C4RealBase(int32_t val, int32_t prec) : value(val) { operator/=(C4RealBase(prec)); }
// Conversion between different implementations of C4RealBase
template<class T>
inline C4RealBase(const C4RealBase<T> &val) : value(static_cast<float>(val)) { }
public:
// constructors
inline C4Fixed () { /*val=0;*/ } // why initialize?
inline C4Fixed (const C4Fixed &rCpy): val(rCpy.val) { }
// Conversion must be done by the conversion routines itofix, fixtoi, ftofix and fixtof
// in order to be backward compatible, so everything is private.
private:
explicit inline C4Fixed(int32_t iVal)
: val (iVal * FIXED_FPF)
{ }
explicit inline C4Fixed(int32_t iVal, int32_t iPrec)
: val( iPrec < FIXED_FPF
? iVal * (FIXED_FPF / iPrec) + (iVal * (FIXED_FPF % iPrec)) / iPrec
: int32_t( int64_t(iVal) * FIXED_FPF / iPrec )
)
{ }
explicit inline C4Fixed(float fVal)
: val(static_cast<int32_t>(fVal * float(FIXED_FPF)))
{ }
// round to int
int32_t to_int() const
{
int32_t r = val;
// be careful not to overflow
r += (val <= 0x7fffffff - FIXED_FPF / 2) * FIXED_FPF / 2;
// ensure that -x.50 is rounded to -(x+1)
r -= (val < 0);
r >>= FIXED_SHIFT;
// round 32767.5 to 32768 (not that anybody cares)
r += (val > 0x7fffffff - FIXED_FPF / 2);
return r;
}
int32_t to_int(int32_t prec) const
{
int64_t r = val;
r *= prec;
r += FIXED_FPF / 2;
r -= (val < 0);
r >>= FIXED_SHIFT;
return int32_t(r);
}
// convert to floating point value
float to_float() const
{
return float(val) / float(FIXED_FPF);
}
public:
// set integer (allowed for historic reasons)
inline C4Fixed &operator = (int32_t x) { return *this = C4Fixed(x); }
// test value
inline operator bool () const { return !! val; }
inline bool operator ! () const { return ! val; }
// Copy ctor and assignment
inline C4RealBase(const C4RealBase &rhs) : value(rhs.value) {}
inline C4RealBase &operator = (const C4RealBase &rhs) { value = rhs.value; return *this; }
inline C4RealBase &operator = (float rhs) { value = C4RealImpl(rhs); return *this; }
inline C4RealBase &operator = (int rhs) { value = C4RealImpl(rhs); return *this; }
// arithmetic operations
inline C4Fixed &operator += (const C4Fixed &fVal2)
{
val += fVal2.val;
return *this;
}
inline C4Fixed &operator -= (const C4Fixed &fVal2)
{
val -= fVal2.val;
return *this;
}
inline C4Fixed &operator *= (const C4Fixed &fVal2)
{
#ifndef FIXED_EMULATE_64BIT
val = int32_t( (int64_t(val) * fVal2.val) / FIXED_FPF );
#else
int32_t x0 = val & (FIXED_FPF - 1),
x1 = val >> FIXED_SHIFT;
int32_t y0 = fVal2.val & (FIXED_FPF - 1),
y1 = fVal2.val >> FIXED_SHIFT;
val = x0*y0/FIXED_FPF + x0*y1 + x1*y0 + x1*y1*FIXED_FPF;
#endif
return *this;
}
inline C4Fixed &operator *= (int32_t iVal2)
{
val *= iVal2;
return *this;
}
inline C4Fixed &operator /= (const C4Fixed &fVal2)
{
val = int32_t( (int64_t(val) * FIXED_FPF) / fVal2.val );
return *this;
}
inline C4Fixed &operator /= (int32_t iVal2)
{
val /= iVal2;
return *this;
}
inline C4Fixed operator - () const
{
C4Fixed fr; fr.val=-val; return fr;
}
inline C4Fixed operator + () const
{
return *this;
#define C4REAL_ARITHMETIC_OPERATOR(op) \
/* combined arithmetic and assignment ops */ \
inline C4RealBase &operator op##= (const C4RealBase &rhs) { value op##= rhs.value; return *this; } \
inline C4RealBase &operator op##= (float rhs) { return *this op##= C4RealBase(rhs); } \
inline C4RealBase &operator op##= (int rhs) { return *this op##= C4RealBase(rhs); } \
/* arithmetic operations on copies */ \
inline C4RealBase operator op (const C4RealBase &rhs) const { C4RealBase nrv(*this); nrv op##= rhs; return nrv; } \
inline C4RealBase operator op (float rhs) const { C4RealBase nrv(*this); nrv op##= rhs; return nrv; } \
inline C4RealBase operator op (int rhs) const { C4RealBase nrv(*this); nrv op##= rhs; return nrv; } \
/* arithmetic operations on copies, right-hand C4Real */ \
/* friends defined in the class are implicitly inline */ \
friend C4RealBase operator op (float lhs, const C4RealBase &rhs) { C4RealBase nrv(lhs); nrv op##= rhs; return nrv; } \
friend C4RealBase operator op (int lhs, const C4RealBase &rhs) { C4RealBase nrv(lhs); nrv op##= rhs; return nrv; }
C4REAL_ARITHMETIC_OPERATOR(+)
C4REAL_ARITHMETIC_OPERATOR(-)
C4REAL_ARITHMETIC_OPERATOR(*)
C4REAL_ARITHMETIC_OPERATOR(/)
#undef C4REAL_ARITHMETIC_OPERATOR
inline C4RealBase operator + () const { return *this; }
inline C4RealBase operator - () const
{
C4RealBase nrv(*this);
nrv.value = -nrv.value;
return nrv;
}
inline bool operator == (const C4Fixed &fVal2) const { return val==fVal2.val; }
inline bool operator < (const C4Fixed &fVal2) const { return val<fVal2.val; }
inline bool operator > (const C4Fixed &fVal2) const { return val>fVal2.val; }
inline bool operator <= (const C4Fixed &fVal2) const { return val<=fVal2.val; }
inline bool operator >= (const C4Fixed &fVal2) const { return val>=fVal2.val; }
inline bool operator != (const C4Fixed &fVal2) const { return val!=fVal2.val; }
#define C4REAL_COMPARISON_OPERATOR(op) \
inline bool operator op (const C4RealBase &rhs) const { return value op rhs.value; } \
inline bool operator op (float rhs) const { return *this op C4RealBase(rhs); } \
inline bool operator op (int rhs) const { return *this op C4RealBase(rhs); }
C4REAL_COMPARISON_OPERATOR(<)
C4REAL_COMPARISON_OPERATOR(<=)
C4REAL_COMPARISON_OPERATOR(==)
C4REAL_COMPARISON_OPERATOR(>=)
C4REAL_COMPARISON_OPERATOR(>)
C4REAL_COMPARISON_OPERATOR(!=)
#undef C4REAL_COMPARISON_OPERATOR
// and wrappers
inline C4Fixed &operator += (int32_t iVal2) { return operator += (C4Fixed(iVal2)); }
inline C4Fixed &operator -= (int32_t iVal2) { return operator -= (C4Fixed(iVal2)); }
// Conversion
inline operator int() const { return value; }
inline operator float() const { return value; }
inline C4Fixed operator + (const C4Fixed &fVal2) const { return C4Fixed(*this) += fVal2; }
inline C4Fixed operator - (const C4Fixed &fVal2) const { return C4Fixed(*this) -= fVal2; }
inline C4Fixed operator * (const C4Fixed &fVal2) const { return C4Fixed(*this) *= fVal2; }
inline C4Fixed operator / (const C4Fixed &fVal2) const { return C4Fixed(*this) /= fVal2; }
// Boolean operators
// Not using safe-bool-idiom here, because we already define conversions
// to integer, which is why we don't need to worry about unwanted con-
// versions via operator bool
inline operator bool() const { return static_cast<bool>(value); }
inline bool operator !() const { return !operator bool(); }
inline C4Fixed operator + (int32_t iVal2) const { return C4Fixed(*this) += iVal2; }
inline C4Fixed operator - (int32_t iVal2) const { return C4Fixed(*this) -= iVal2; }
inline C4Fixed operator * (int32_t iVal2) const { return C4Fixed(*this) *= iVal2; }
inline C4Fixed operator / (int32_t iVal2) const { return C4Fixed(*this) /= iVal2; }
// C++03 doesn't support explicitly defaulted ctors, so C4RealBase can't
// be a POD, so we can't directly store it into unions. Find a type that
// allows this.
template<class T, class IsPOD> struct StorageTypeSelector;
template<class T>
struct StorageTypeSelector<T, boost::false_type> { T v; };
template<class T>
struct StorageTypeSelector<T, boost::true_type> { typename T::StorageType v; };
#if defined(_MSC_VER) && _MSC_VER <= 1200
inline C4Fixed operator + (int iVal2) const { return operator + (int32_t(iVal2)); }
inline C4Fixed operator - (int iVal2) const { return operator - (int32_t(iVal2)); }
inline C4Fixed operator * (int iVal2) const { return operator * (int32_t(iVal2)); }
inline C4Fixed operator / (int iVal2) const { return operator / (int32_t(iVal2)); }
#endif
typedef StorageTypeSelector<C4RealImpl, typename boost::is_class<C4RealImpl>::type> StorageType;
static_assert(boost::is_pod<StorageType>::value, "C4RealBase: StorageType is not a POD type");
inline bool operator == (int32_t iVal2) const { return operator == (C4Fixed(iVal2)); }
inline bool operator < (int32_t iVal2) const { return operator < (C4Fixed(iVal2)); }
inline bool operator > (int32_t iVal2) const { return operator > (C4Fixed(iVal2)); }
inline bool operator <= (int32_t iVal2) const { return operator <= (C4Fixed(iVal2)); }
inline bool operator >= (int32_t iVal2) const { return operator >= (C4Fixed(iVal2)); }
inline bool operator != (int32_t iVal2) const { return operator != (C4Fixed(iVal2)); }
#if defined(_MSC_VER) && _MSC_VER <= 1200
inline bool operator == (int iVal2) const { return operator == (C4Fixed(int32_t(iVal2))); }
inline bool operator < (int iVal2) const { return operator < (C4Fixed(int32_t(iVal2))); }
inline bool operator > (int iVal2) const { return operator > (C4Fixed(int32_t(iVal2))); }
inline bool operator <= (int iVal2) const { return operator <= (C4Fixed(int32_t(iVal2))); }
inline bool operator >= (int iVal2) const { return operator >= (C4Fixed(int32_t(iVal2))); }
inline bool operator != (int iVal2) const { return operator != (C4Fixed(int32_t(iVal2))); }
#endif
#ifdef C4REAL_USE_FIXNUM
C4Fixed sin_deg() const
{
// adjust angle
int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=18000-v; v%=36000;
// get sine
C4Fixed fr;
switch (v/9000)
{
case 0: fr.val=+SineTable[v]; break;
case 1: fr.val=+SineTable[18000-v]; break;
case 2: fr.val=-SineTable[v-18000]; break;
case 3: fr.val=-SineTable[36000-v]; break;
}
return fr;
}
C4Fixed cos_deg() const
{
// adjust angle
int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=-v; v%=36000;
// get cosine
C4Fixed fr;
switch (v/9000)
{
case 0: fr.val=+SineTable[9000-v]; break;
case 1: fr.val=-SineTable[v-9000]; break;
case 2: fr.val=-SineTable[27000-v]; break;
case 3: fr.val=+SineTable[v-27000]; break;
}
return fr;
}
#endif
friend bool operator==(StorageType lhs, StorageType rhs) { return lhs.v == rhs.v; }
C4RealBase(StorageType rhs) : value(rhs.v) {}
operator StorageType() const { StorageType nrv = {value}; return nrv; }
};
#ifdef C4REAL_USE_FIXNUM
typedef C4RealBase<class C4RealImpl_Fixed> C4Real_Fixed;
typedef C4RealBase<float> C4Real_FPU_Float;
typedef C4RealBase<class C4RealImpl_SSE> C4Real_SSE_Float;
typedef C4Fixed C4Real;
#include "C4RealImpl_Fixed.h"
#include "C4RealImpl_FPU.h"
#include "C4RealImpl_SSE.h"
// *** wrap C4Real to requested C4RealBase instantiation
#if C4REAL_MODE == C4REAL_MODE_SOFTWARE
typedef C4Real_Fixed C4Real;
#elif C4REAL_MODE == C4REAL_MODE_FPU_FLOAT
typedef C4Real_FPU_Float C4Real;
#elif C4REAL_MODE == C4REAL_MODE_SSE_FLOAT
typedef C4Real_SSE_Float C4Real;
#endif
// Instantiate other C4RealBases as well
template class C4RealBase<C4RealImpl_Fixed>;
template class C4RealBase<float>;
template class C4RealBase<C4RealImpl_SSE>;
// conversion
inline float fixtof(const C4Fixed &x) { return x.to_float(); }
inline C4Fixed ftofix(float x) { return C4Fixed(x); }
inline int fixtoi(const C4Fixed &x) { return x.to_int(); }
inline int fixtoi(const C4Fixed &x, int32_t prec) { return x.to_int(prec); }
inline C4Fixed itofix(int32_t x) { return C4Fixed(x); }
inline C4Fixed itofix(int32_t x, int32_t prec) { return C4Fixed(x, prec); }
inline float fixtof(const C4Real &x) { return static_cast<float>(x); }
inline C4Real ftofix(float x) { return C4Real(x); }
inline int fixtoi(const C4Real &x) { return static_cast<int>(x); }
inline int fixtoi(const C4Real &x, int32_t prec) { return static_cast<int>(x * prec); }
inline C4Real itofix(int32_t x) { return C4Real(x); }
inline C4Real itofix(int32_t x, int32_t prec) { return C4Real(x, prec); }
// additional functions
inline C4Real Sin(const C4Real &fAngle) { return fAngle.sin_deg(); }
inline C4Real Cos(const C4Real &fAngle) { return fAngle.cos_deg(); }
inline C4Real C4REAL100(int x) { return itofix(x, 100); }
//inline C4Real C4REAL256(int x) { return itofix(x, 256); }
inline C4Real C4REAL256(int x) { C4Fixed r; r.val = x * FIXED_FPF / 256; return r; }
inline C4Real C4REAL10(int x) { return itofix(x, 10); }
inline C4Real C4REAL100(int x) { C4Real nrv(x); nrv /= 100; return nrv; }
inline C4Real C4REAL256(int x) { C4Real nrv(x); nrv /= 256; return nrv; }
inline C4Real C4REAL10(int x) { C4Real nrv(x); nrv /= 10; return nrv; }
#else
// *** wrap C4Real to float
typedef float C4Real;
// fixtoi: use asm fistp, round up
inline int fixtoi(C4Real x)
{
int e;
#ifdef _MSC_VER
float y = x;
_asm
{
or y,1;
fld y;
fistp e;
}
#else
asm ("or $1, %0" : "+rom" (x));
asm ("fistp%z0 %0" : "=om" (e) : "t" (x) : "st");
#endif
return e;
}
// conversion
inline int fixtoi(const C4Real &x, int32_t prec) { return fixtoi(x*prec); }
inline C4Real itofix(int x) { return static_cast<C4Real>(x); }
inline C4Real itofix(int x, int prec) { return static_cast<C4Real>(x) / prec; }
inline float fixtof(const C4Real &x) { return x; }
inline C4Real ftofix(float x) { return x; }
// additional functions
inline C4Real Sin(C4Real x) { return float(sin(x * 3.141592f / 180)); }
inline C4Real Cos(C4Real x) { return float(cos(x * 3.141592f / 180)); }
inline C4Real C4REAL100(int x) { return float(x) / 100; }
inline C4Real C4REAL256(int x) { return float(x) / 256; }
inline C4Real C4REAL10(int x) { return float(x) / 10; }
#endif
// define 0
const C4Real Fix0 = itofix(0);
// conversion...
// note: keep out! really dirty casts!
#ifdef C4REAL_USE_FIXNUM
inline void FLOAT_TO_FIXED(C4Real *pVal)
{
*pVal = ftofix (*reinterpret_cast<float *>(pVal));
}
#else
inline void FIXED_TO_FLOAT(C4Real *pVal)
{
*pVal = reinterpret_cast<C4Fixed *>(pVal)->to_float();
}
#endif
#undef inline
const C4Real Fix0 = C4Real(0);
// CompileFunc for C4Real
void CompileFunc(C4Real &rValue, StdCompiler *pComp);
#endif //FIXED_H_INC
#endif //C4REAL_H_INC

View File

@ -0,0 +1,78 @@
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2010 Nicolas Hake
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* See isc_license.txt for full license and disclaimer.
*
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
/* Fixed point math extracted from ALLEGRO by Shawn Hargreaves */
#ifndef INC_RealImpl_FPU
#define INC_RealImpl_FPU
#ifndef INC_C4Real
#error C4RealImpl_FPU.h must not be included by itself; include C4Real.h instead
#endif
#ifdef _MSC_VER
# define _USE_MATH_DEFINES
#endif
#include <cmath>
inline C4Real_FPU_Float Sin(const C4Real_FPU_Float &real)
{
return C4Real_FPU_Float(std::sin(real.value * static_cast<float>(M_PI) / 180.0f));
}
inline C4Real_FPU_Float Cos(const C4Real_FPU_Float &real)
{
return C4Real_FPU_Float(std::cos(real.value * static_cast<float>(M_PI) / 180.0f));
}
// Overload to avoid conversion warning
template<>
inline C4Real_FPU_Float::operator bool () const
{
return value != 0.0f;
}
// C4Real_Fixed rounds up. Why?
#ifdef _M_X64
#include <xmmintrin.h>
#endif
template<>
inline C4Real_FPU_Float::operator int () const
{
float y = value;
#if defined _M_X64
*reinterpret_cast<int*>(&y) |= 1;
return _mm_cvtss_si32(_mm_load_ss(&y));
#elif defined _MSC_VER
int e;
_asm
{
or y,1;
fld y;
fistp e;
}
return e;
#elif defined __GNUC__
int e;
asm ("or $1, %0" : "+rom" (y));
asm ("fistp%z0 %0" : "=om" (e) : "t" (y) : "st");
return e;
#else
#error Unknown processor; implement rounding here
#endif
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,190 @@
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 1998-2000 Matthes Bender
* Copyright (c) 2002, 2005 Sven Eberhardt
* Copyright (c) 2002, 2004-2005, 2007 Peter Wortmann
* Copyright (c) 2005, 2007 Günther Brammer
* Copyright (c) 2010 Nicolas Hake
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* See isc_license.txt for full license and disclaimer.
*
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
/* Fixed point math extracted from ALLEGRO by Shawn Hargreaves */
#ifndef INC_RealImpl_Fixed
#define INC_RealImpl_Fixed
#ifndef INC_C4Real
#error C4RealImpl_Fixed.h must not be included by itself; include C4Real.h instead
#endif
#define FIXED_EMULATE_64BIT
#include <boost/operators.hpp>
class C4RealImpl_Fixed
: boost::totally_ordered<C4RealImpl_Fixed,
boost::equivalent<C4RealImpl_Fixed
> >
{
// fixpoint shift (check 64 bit emulation before changing!)
static const int32_t FIXED_SHIFT = 16;
static const int32_t FIXED_FPF = 1 << FIXED_SHIFT;
int32_t val; // Internal value
static long SineTable[9001]; // external table of sine values
public:
struct StorageType { int32_t v; };
friend bool operator==(StorageType lhs, StorageType rhs) { return lhs.v == rhs.v; }
inline C4RealImpl_Fixed() : val(0) {}
inline C4RealImpl_Fixed(const C4RealImpl_Fixed &rhs) : val(rhs.val) {}
explicit inline C4RealImpl_Fixed(int32_t iVal) : val (iVal * FIXED_FPF) { }
explicit inline C4RealImpl_Fixed(int32_t iVal, int32_t iPrec)
: val( iPrec < FIXED_FPF
? iVal * (FIXED_FPF / iPrec) + (iVal * (FIXED_FPF % iPrec)) / iPrec
: int32_t( int64_t(iVal) * FIXED_FPF / iPrec )
)
{ }
explicit inline C4RealImpl_Fixed(float fVal)
: val(static_cast<int32_t>(fVal * float(FIXED_FPF)))
{ }
inline C4RealImpl_Fixed(StorageType rhs) : val(rhs.v) {}
operator StorageType() const { StorageType nrv = {val}; return nrv; }
int32_t to_int() const
{
int32_t r = val;
// be careful not to overflow
r += (val <= 0x7fffffff - FIXED_FPF / 2) * FIXED_FPF / 2;
// ensure that -x.50 is rounded to -(x+1)
r -= (val < 0);
r >>= FIXED_SHIFT;
// round 32767.5 to 32768 (not that anybody cares)
r += (val > 0x7fffffff - FIXED_FPF / 2);
return r;
}
int32_t to_int(int32_t prec) const
{
int64_t r = val;
r *= prec;
r += FIXED_FPF / 2;
r -= (val < 0);
r >>= FIXED_SHIFT;
return int32_t(r);
}
// convert to floating point value
float to_float() const
{
return float(val) / float(FIXED_FPF);
}
// Arithmetics.
C4RealImpl_Fixed &operator += (const C4RealImpl_Fixed &rhs)
{
val += rhs.val;
return *this;
}
C4RealImpl_Fixed &operator -= (const C4RealImpl_Fixed &rhs)
{
val -= rhs.val;
return *this;
}
C4RealImpl_Fixed &operator *= (const C4RealImpl_Fixed &rhs)
{
#ifndef FIXED_EMULATE_64BIT
val = int32_t( (int64_t(val) * rhs.val) / FIXED_FPF );
#else
int32_t x0 = val & (FIXED_FPF - 1),
x1 = val >> FIXED_SHIFT;
int32_t y0 = rhs.val & (FIXED_FPF - 1),
y1 = rhs.val >> FIXED_SHIFT;
val = x0*y0/FIXED_FPF + x0*y1 + x1*y0 + x1*y1*FIXED_FPF;
#endif
return *this;
}
C4RealImpl_Fixed &operator /= (const C4RealImpl_Fixed &rhs)
{
val = int32_t( (int64_t(val) * FIXED_FPF) / rhs.val );
return *this;
}
C4RealImpl_Fixed operator - ()
{
C4RealImpl_Fixed nrv(*this);
nrv.val = -nrv.val;
return nrv;
}
C4RealImpl_Fixed sin_deg() const
{
// adjust angle
int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=18000-v; v%=36000;
// get sine
C4RealImpl_Fixed fr;
switch (v/9000)
{
case 0: fr.val=+SineTable[v]; break;
case 1: fr.val=+SineTable[18000-v]; break;
case 2: fr.val=-SineTable[v-18000]; break;
case 3: fr.val=-SineTable[36000-v]; break;
}
return fr;
}
C4RealImpl_Fixed cos_deg() const
{
// adjust angle
int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=-v; v%=36000;
// get cosine
C4RealImpl_Fixed fr;
switch (v/9000)
{
case 0: fr.val=+SineTable[9000-v]; break;
case 1: fr.val=-SineTable[v-9000]; break;
case 2: fr.val=-SineTable[27000-v]; break;
case 3: fr.val=+SineTable[v-27000]; break;
}
return fr;
}
// Comparison
bool operator < (const C4RealImpl_Fixed &rhs) const { return val < rhs.val; }
operator bool () const { return val != 0; }
// Conversion
operator float () const { return to_float(); }
operator int () const { return to_int(); }
};
// Avoid overflowing
template<>
inline C4RealBase<C4RealImpl_Fixed>::C4RealBase(int32_t val, int32_t prec)
: value(val, prec)
{}
inline C4Real_Fixed Sin(const C4Real_Fixed &real)
{
C4Real_Fixed nrv;
nrv.value = real.value.sin_deg();
return nrv;
}
inline C4Real_Fixed Cos(const C4Real_Fixed &real)
{
C4Real_Fixed nrv;
nrv.value = real.value.cos_deg();
return nrv;
}
#endif

View File

@ -0,0 +1,118 @@
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2010 Nicolas Hake
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* See isc_license.txt for full license and disclaimer.
*
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
#include "C4Include.h"
#include "C4Real.h"
// Constants required for sine approximation
const __m128 C4RealImpl_SSE::cephes_deg2rad = _mm_set_ps1(0.017453292f); // pi/180
const __m128 C4RealImpl_SSE::cephes_FOPI = _mm_set_ps1(1.27323954473516f); // 4/pi
const __m128 C4RealImpl_SSE::cephes_scaling_factors[3] = {
_mm_set_ps1(0.78515625f), _mm_set_ps1(2.4187564849853515625e-4f), _mm_set_ps1(3.77489497744594108e-8f)
};
const __m128 C4RealImpl_SSE::cephes_appx_coeffs[3] = {
_mm_set_ps(-1.9515295891e-4f, 2.443315711809948e-5f, 2.443315711809948e-5f, -1.9515295891e-4f),
_mm_set_ps(8.3321608736e-3f, -1.388731625493765e-3f, -1.388731625493765e-3f, 8.3321608736e-3f),
_mm_set_ps(-1.6666654611e-1f, 4.166664568298827e-2f, 4.166664568298827e-2f, -1.6666654611e-1f)
};
const __m128 C4RealImpl_SSE::iee754_sign_mask = _mm_set_ps1(-0.0f);
// Branchless approximation of sine and cosine values
C4RealImpl_SSE C4RealImpl_SSE::SinCos(bool cosine) const
{
// NOTE: Consider storing radians directly instead of degrees to avoid
// precision loss due to conversion
__m128 radian = _mm_mul_ps(value, cephes_deg2rad);
#ifndef NDEBUG
float float_radians; _mm_store_ss(&float_radians, radian);
#endif
// put rad into all parts of the xmm register
radian = _mm_shuffle_ps(radian, radian, 0);
// cephes library sine/cosine implementation
// This calculates a Taylor approximation of rank 7 with slightly
// modified coefficients to achieve better precision on the reduced
// input range -pi/4..pi/4.
union m128extract {
float f[4];
uint32_t i[4];
__m128 v;
};
// Store sign and take absolute value of input
__m128 sign = _mm_and_ps(radian, iee754_sign_mask);
radian = _mm_xor_ps(radian, sign);
m128extract sign_bits;
sign_bits.v = sign;
// Select octant of the unit circle
__m128 scaling = _mm_mul_ps(radian, C4RealImpl_SSE::cephes_FOPI);
int octant = _mm_cvttss_si32(scaling);
octant = (octant + 1) & ~1;
scaling = _mm_cvtsi32_ss(scaling, octant);
scaling = _mm_shuffle_ps(scaling, scaling, 0);
uint32_t flip_sign_sine = ((octant & 4) << 29);
octant &= 3;
uint32_t flip_sign_cosine = flip_sign_sine ^ ((octant & 2) << 30);
flip_sign_sine ^= sign_bits.i[0];
// map input to +-pi/4
// note that this get more and more imprecise for abs(radian) > 8192
radian = _mm_sub_ps(radian, _mm_mul_ps(scaling, cephes_scaling_factors[0]));
radian = _mm_sub_ps(radian, _mm_mul_ps(scaling, cephes_scaling_factors[1]));
radian = _mm_sub_ps(radian, _mm_mul_ps(scaling, cephes_scaling_factors[2]));
// run approximation, calculating four octants at once; correct result
// will be selected later
__m128 radiansq = _mm_mul_ps(radian, radian);
__m128 result = cephes_appx_coeffs[0];
result = _mm_mul_ps(result, radiansq);
result = _mm_add_ps(result, cephes_appx_coeffs[1]);
result = _mm_mul_ps(result, radiansq);
result = _mm_add_ps(result, cephes_appx_coeffs[2]);
result = _mm_mul_ps(result, radiansq);
radiansq = _mm_shuffle_ps(radiansq, radian, _MM_SHUFFLE(0,0,0,0));
radiansq = _mm_shuffle_ps(radiansq, radiansq, _MM_SHUFFLE(2,0,0,2));
result = _mm_mul_ps(result, radiansq);
radiansq = _mm_mul_ps(radiansq, _mm_set_ps(1.0f, -0.5f, -0.5f, 1.0f));
result = _mm_add_ps(result, radiansq);
result = _mm_add_ps(result, _mm_set_ps(0.0f, 1.0f, 1.0f, 0.0f));
// Select correct octant
m128extract rv;
rv.v = result;
int sinidx = octant;
int cosidx = octant ^ 2;
// adjust sign
rv.i[sinidx] ^= flip_sign_sine;
rv.i[cosidx] ^= flip_sign_cosine;
// relative error less than 1.1e-6 for input values between -360 deg
// and 360 deg
// relative error less than 1.2e-7 between -260 deg and 260 deg.
// absolute error less than 6.0e-8 between -4.2e7 and 4.2e7 deg.
assert(float_radians == 0.0f || std::abs((rv.f[sinidx] - std::sinf(float_radians)) / std::sinf(float_radians)) < 1.1e-6f);
assert(float_radians == 0.0f || std::abs((rv.f[cosidx] - std::cosf(float_radians)) / std::cosf(float_radians)) < 1.1e-6f);
uint32_t cosine_mask = cosine * ~0;
int idx = (cosine_mask & cosidx) | (~cosine_mask & sinidx);
return rv.f[idx];
}

View File

@ -0,0 +1,124 @@
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2010 Nicolas Hake
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* See isc_license.txt for full license and disclaimer.
*
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
#ifndef INC_RealImpl_SSE
#define INC_RealImpl_SSE
#ifndef INC_C4Real
#error C4RealImpl_SSE.h must not be included by itself; include C4Real.h instead
#endif
#include <cassert>
#include <xmmintrin.h>
class C4RealImpl_SSE
{
friend C4Real_SSE_Float Sin(const C4Real_SSE_Float &);
friend C4Real_SSE_Float Cos(const C4Real_SSE_Float &);
__m128 value;
static const __m128 iee754_sign_mask; // -0.0
static const __m128 cephes_FOPI; // 4/pi
static const __m128 cephes_deg2rad; // pi/180
static const __m128 cephes_appx_coeffs[3]; // approximation coefficients
static const __m128 cephes_scaling_factors[3]; // factors for quick scaling to -pi/4..pi/4
C4RealImpl_SSE SinCos(bool cosine) const; // approximation of sine and cosine
public:
inline C4RealImpl_SSE()
: value(_mm_setzero_ps())
{}
inline C4RealImpl_SSE(const C4RealImpl_SSE &rhs)
: value(rhs.value)
{}
inline C4RealImpl_SSE(int32_t iVal)
: value(_mm_cvtsi32_ss(value, iVal))
{}
inline C4RealImpl_SSE(float fVal)
: value(_mm_set_ss(fVal))
{}
operator int () const
{
return _mm_cvtss_si32(value);
}
operator float () const
{
float f;
_mm_store_ss(&f, value);
return f;
}
// To store C4RealImpl_SSE into unions, we're using an anonymous struct
// to distinguish types, and an int32_t inside that struct to avoid passing
// parameters via the x87 stack.
struct StorageType { int32_t v; };
friend bool operator==(StorageType lhs, StorageType rhs) { return lhs.v == rhs.v; }
inline C4RealImpl_SSE(StorageType rhs)
: value(_mm_load_ss(reinterpret_cast<float*>(&rhs.v)))
{}
operator StorageType() const
{
StorageType nrv;
_mm_store_ss(reinterpret_cast<float*>(&nrv.v), value);
return nrv;
}
// Arithmetics
// We're using _ps intrinsics for everything except division because they
// have the same latency as their _ss counterparts, but their representa-
// tion is one byte shorter (0F xx instead of F3 0F xx).
// DIVPS is about half as fast as DIVSS, so we use the scalar instruction
// here.
C4RealImpl_SSE &operator += (const C4RealImpl_SSE &rhs) { value = _mm_add_ps(value, rhs.value); return *this; }
C4RealImpl_SSE &operator -= (const C4RealImpl_SSE &rhs) { value = _mm_sub_ps(value, rhs.value); return *this; }
C4RealImpl_SSE &operator *= (const C4RealImpl_SSE &rhs) { value = _mm_mul_ps(value, rhs.value); return *this; }
C4RealImpl_SSE &operator /= (const C4RealImpl_SSE &rhs) { value = _mm_div_ss(value, rhs.value); return *this; }
// Negation
C4RealImpl_SSE operator - () const
{
C4RealImpl_SSE nrv;
nrv -= *this;
return nrv;
}
// Comparison
// COMISS is faster on newer CPUs than CMPSS, also we get a nice return
// value from the intrinsic instead of having to store parts of the XMM
// register to a variable to read.
bool operator < (const C4RealImpl_SSE &rhs) const { return _mm_comilt_ss(value, rhs.value) != 0; }
bool operator <= (const C4RealImpl_SSE &rhs) const { return _mm_comile_ss(value, rhs.value) != 0; }
bool operator == (const C4RealImpl_SSE &rhs) const { return _mm_comieq_ss(value, rhs.value) != 0; }
bool operator >= (const C4RealImpl_SSE &rhs) const { return _mm_comige_ss(value, rhs.value) != 0; }
bool operator > (const C4RealImpl_SSE &rhs) const { return _mm_comigt_ss(value, rhs.value) != 0; }
bool operator != (const C4RealImpl_SSE &rhs) const { return _mm_comineq_ss(value, rhs.value) != 0; }
operator bool () const { return _mm_comineq_ss(value, _mm_setzero_ps()) != 0; }
bool operator ! () const { return _mm_comieq_ss(value, _mm_setzero_ps()) != 0; }
};
inline C4Real_SSE_Float Sin(const C4Real_SSE_Float &real)
{
return C4Real_SSE_Float(static_cast<float>(real.value.SinCos(false)));
}
inline C4Real_SSE_Float Cos(const C4Real_SSE_Float &real)
{
return C4Real_SSE_Float(static_cast<float>(real.value.SinCos(true)));
}
#endif

View File

@ -70,6 +70,7 @@ void StdCompilerBinWrite::Byte(int8_t &rByte) { WriteValue(rByte); }
void StdCompilerBinWrite::Byte(uint8_t &rByte) { WriteValue(rByte); }
void StdCompilerBinWrite::Boolean(bool &rBool) { WriteValue(rBool); }
void StdCompilerBinWrite::Character(char &rChar) { WriteValue(rChar); }
void StdCompilerBinWrite::Float(float &val) { WriteValue(val); }
void StdCompilerBinWrite::String(char *szString, size_t iMaxLength, RawCompileType eType)
{
WriteData(szString, strlen(szString) + 1);
@ -128,6 +129,7 @@ void StdCompilerBinRead::Byte(int8_t &rByte) { ReadValue(rByte); }
void StdCompilerBinRead::Byte(uint8_t &rByte) { ReadValue(rByte); }
void StdCompilerBinRead::Boolean(bool &rBool) { ReadValue(rBool); }
void StdCompilerBinRead::Character(char &rChar) { ReadValue(rChar); }
void StdCompilerBinRead::Float(float &val) { ReadValue(val); }
void StdCompilerBinRead::String(char *szString, size_t iMaxLength, RawCompileType eType)
{
// At least one byte data needed
@ -281,6 +283,12 @@ void StdCompilerINIWrite::Character(char &rChar)
PrepareForValue();
Buf.AppendFormat("%c", rChar);
}
void StdCompilerINIWrite::Float(float &val)
{
PrepareForValue();
Buf.AppendFormat("%f", val);
}
void StdCompilerINIWrite::String(char *szString, size_t iMaxLength, RawCompileType eType)
{
@ -613,6 +621,31 @@ void StdCompilerINIRead::Character(char &rChar)
{ notFound("Character"); return; }
rChar = *pPos++;
}
void StdCompilerINIRead::Float(float &val)
{
if (!pPos)
{ notFound("Float"); return; }
// Skip whitespace
SkipWhitespace();
// Read number.
const char *pnPos = pPos;
double num = strtod(pPos, const_cast<char **>(&pnPos));
// Could not read?
if (!num && pnPos == pPos)
{ notFound("Float"); return; }
if (num < std::numeric_limits<float>::min() || num > std::numeric_limits<float>::max())
{
Warn("number out of range (%f to %f): %f ",
static_cast<double>(std::numeric_limits<float>::min()),
static_cast<double>(std::numeric_limits<float>::max()),
num);
if (num < std::numeric_limits<float>::min()) num = std::numeric_limits<float>::min();
else if (num > std::numeric_limits<float>::max()) num = std::numeric_limits<float>::max();
}
// Get over it
pPos = pnPos;
val = num;
}
void StdCompilerINIRead::String(char *szString, size_t iMaxLength, RawCompileType eType)
{
// Read data

View File

@ -139,6 +139,7 @@ public:
virtual void Byte(uint8_t &rByte) = 0; // Needs separator!
virtual void Boolean(bool &rBool) = 0;
virtual void Character(char &rChar) = 0; // Alphanumerical only!
virtual void Float(float &val) = 0;
// Compile raw data (strings)
@ -177,6 +178,7 @@ public:
void Value(int8_t &rInt) { Byte(rInt); }
void Value(uint8_t &rInt) { Byte(rInt); }
void Value(bool &rBool) { Boolean(rBool); }
void Value(float &val) { Float(val); }
// Compiling/Decompiling (may throw a data format exception!)
template <class T> inline void Compile(T RREF rStruct)
@ -434,6 +436,7 @@ public:
virtual void Byte(uint8_t &rByte) { }
virtual void Boolean(bool &rBool) { }
virtual void Character(char &rChar) { }
virtual void Float(float &val) { }
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped) { }
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped) { }
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped) { }
@ -466,6 +469,7 @@ public:
virtual void Byte(uint8_t &rByte);
virtual void Boolean(bool &rBool);
virtual void Character(char &rChar);
virtual void Float(float &val);
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
@ -506,6 +510,7 @@ public:
virtual void Byte(uint8_t &rByte);
virtual void Boolean(bool &rBool);
virtual void Character(char &rChar);
virtual void Float(float &val);
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
@ -584,6 +589,7 @@ public:
virtual void Byte(uint8_t &rByte);
virtual void Boolean(bool &rBool);
virtual void Character(char &rChar);
virtual void Float(float &val);
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
@ -655,6 +661,7 @@ public:
virtual void Byte(uint8_t &rByte);
virtual void Boolean(bool &rBool);
virtual void Character(char &rChar);
virtual void Float(float &val);
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);

View File

@ -136,6 +136,13 @@ typedef ptrdiff_t ssize_t;
#ifndef HAVE_STATIC_ASSERT
#include <boost/static_assert.hpp>
#define static_assert(x, y) BOOST_STATIC_ASSERT(x)
#endif
#if defined(__GNUC__)
// Allow checks for correct printf-usage
#define GNUC_FORMAT_ATTRIBUTE __attribute__ ((format (printf, 1, 2)))

View File

@ -516,6 +516,11 @@ void StdCompilerConfigWrite::Raw(void *pData, size_t iSize, RawCompileType eType
excCorrupt("Raw values aren't supported for registry compilers!");
}
void StdCompilerConfigWrite::Float(float &val)
{
excCorrupt(0, "Float values aren't supported for registry compilers!");
}
void StdCompilerConfigWrite::Begin()
{
assert(!iDepth);
@ -699,6 +704,11 @@ void StdCompilerConfigRead::Raw(void *pData, size_t iSize, RawCompileType eType)
excCorrupt(0, "Raw values aren't supported for registry compilers!");
}
void StdCompilerConfigRead::Float(float &val)
{
excCorrupt(0, "Float values aren't supported for registry compilers!");
}
void StdCompilerConfigRead::Begin()
{
assert(!iDepth);

View File

@ -106,6 +106,7 @@ public:
virtual void Byte(uint8_t &rByte);
virtual void Boolean(bool &rBool);
virtual void Character(char &rChar);
virtual void Float(float &val);
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
@ -162,6 +163,7 @@ public:
virtual void Byte(uint8_t &rByte);
virtual void Boolean(bool &rBool);
virtual void Character(char &rChar);
virtual void Float(float &val);
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);

View File

@ -192,6 +192,7 @@ enum C4AulBCCType
AB_CALLFS, // failsafe direct call
AB_STACK, // push nulls / pop
AB_INT, // constant: int
AB_FLOAT, // constant: float
AB_BOOL, // constant: bool
AB_STRING, // constant: string
AB_C4ID, // constant: C4ID
@ -238,6 +239,7 @@ struct C4AulBCC
union
{
int32_t i;
C4Real::StorageType fl;
C4String * s;
C4AulFunc * f;
intptr_t X;

View File

@ -173,6 +173,10 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
PushValue(C4VInt(pCPos->Par.i));
break;
case AB_FLOAT:
PushValue(C4VFloat(pCPos->Par.fl));
break;
case AB_BOOL:
PushValue(C4VBool(!! pCPos->Par.i));
break;
@ -274,7 +278,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
if (!pPar2->_getInt())
throw new C4AulExecError(pCurCtx->Obj, "Division by zero");
pPar1->SetInt(pPar1->_getInt() / pPar2->_getInt());
pPar1->Deref();
*pPar1 /= *pPar2;
PopValue();
break;
}
@ -282,7 +287,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
{
CheckOpPars(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
pPar1->SetInt(pPar1->_getInt() * pPar2->_getInt());
pPar1->Deref();
*pPar1 *= *pPar2;
PopValue();
break;
}
@ -301,7 +307,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
{
CheckOpPars(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
pPar1->SetInt(pPar1->_getInt() - pPar2->_getInt());
pPar1->Deref();
*pPar1 -= *pPar2;
PopValue();
break;
}
@ -309,7 +316,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
{
CheckOpPars(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
pPar1->SetInt(pPar1->_getInt() + pPar2->_getInt());
pPar1->Deref();
*pPar1 += *pPar2;
PopValue();
break;
}
@ -405,7 +413,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
{
CheckOpPars3(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
*pPar1 *= pPar2 ->_getInt();
*pPar1 *= *pPar2;
PopValue();
break;
}
@ -415,7 +423,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
if (!pPar2->_getInt())
throw new C4AulExecError(pCurCtx->Obj, "Division by zero");
*pPar1 /= pPar2->_getInt();
*pPar1 /= *pPar2;
PopValue();
break;
}
@ -433,7 +441,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
{
CheckOpPars3(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
*pPar1 += pPar2 ->_getInt();
*pPar1 += *pPar2;
PopValue();
break;
}
@ -441,7 +449,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
{
CheckOpPars3(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
*pPar1 -= pPar2 ->_getInt();
*pPar1 -= *pPar2;
PopValue();
break;
}

View File

@ -96,6 +96,7 @@ enum C4AulTokenType
ATT_DIR, // directive
ATT_IDTF, // identifier
ATT_INT, // integer constant
ATT_FLOAT, // floating point constant
ATT_BOOL, // boolean constant
ATT_STRING, // string constant
ATT_NIL, // "nil"
@ -436,11 +437,11 @@ C4ScriptOpDef C4ScriptOpMap[] =
// postfix
{ 14, "**", AB_Pow, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 13, "/", AB_Div, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 13, "*", AB_Mul, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 13, "/", AB_Div, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
{ 13, "*", AB_Mul, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
{ 13, "%", AB_Mod, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 12, "-", AB_Sub, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 12, "+", AB_Sum, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 12, "-", AB_Sub, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
{ 12, "+", AB_Sum, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
{ 11, "<<", AB_LeftShift, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 11, ">>", AB_RightShift, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 10, "<", AB_LessThan, 1, 0, 0, C4V_Bool, C4V_Int, C4V_Int},
@ -454,11 +455,11 @@ C4ScriptOpDef C4ScriptOpMap[] =
{ 6, "|", AB_BitOr, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 5, "&&", AB_JUMPAND, 1, 0, 0, C4V_Bool, C4V_Bool, C4V_Bool},
{ 4, "||", AB_JUMPOR, 1, 0, 0, C4V_Bool, C4V_Bool, C4V_Bool},
{ 2, "*=", AB_MulIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "/=", AB_DivIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "*=", AB_MulIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
{ 2, "/=", AB_DivIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
{ 2, "%=", AB_ModIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "+=", AB_Inc, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "-=", AB_Dec, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "+=", AB_Inc, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
{ 2, "-=", AB_Dec, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
{ 2, "&=", AB_AndIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "|=", AB_OrIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "^=", AB_XOrIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
@ -545,6 +546,11 @@ static int32_t StrToI32(char *s, int base, char **scan_end)
return result;
}
static float StrToF32(const char *s, char **scan_end)
{
return strtod(s, scan_end);
}
void C4AulParseState::ClearToken()
{
// if last token was a string, make sure its ref is deleted
@ -571,6 +577,7 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
TGS_Ident, // getting identifier
TGS_Int, // getting integer
TGS_IntHex, // getting hexadecimal integer
TGS_Float, // getting floating point value
TGS_String, // getting string
TGS_Dir // getting directive
};
@ -709,6 +716,13 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
break;
case TGS_Int: // integer: parse until non-number is found
if (C == '.')
{
State = TGS_Float;
break;
}
else
// Fall through
case TGS_IntHex:
if ((C < '0') || (C > '9'))
{
@ -741,6 +755,17 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
}
break;
case TGS_Float: // float (after decimal point): parse until non-numeric
if ((C < '0') || (C > '9'))
{
Len = Min(Len, C4AUL_MAX_Identifier);
SCopy(SPos0, pToken, Len);
float value = StrToF32(pToken, 0);
*pInt = *reinterpret_cast<int*>(&value);
return ATT_FLOAT;
}
break;
case TGS_String: // string: parse until '"'; check for eof!
// string end
@ -1020,6 +1045,7 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
switch (eType)
{
case AB_INT:
case AB_FLOAT:
case AB_BOOL:
case AB_STRING:
case AB_C4ID:
@ -2439,6 +2465,12 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
switch (val.GetType())
{
case C4V_Int: AddBCC(AB_INT, val.GetData().Int); break;
case C4V_Float:
{
C4Real::StorageType f = val.getFloat();
AddBCC(AB_FLOAT, *reinterpret_cast<intptr_t*>(&f));
break;
}
case C4V_Bool: AddBCC(AB_BOOL, val.GetData().Int); break;
case C4V_String:
AddBCC(AB_STRING, reinterpret_cast<intptr_t>(val._getStr()));
@ -2474,6 +2506,12 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
Shift();
break;
}
case ATT_FLOAT: // constant in cInt
{
AddBCC(AB_FLOAT, cInt);
Shift();
break;
}
case ATT_BOOL: // constant in cInt
{
AddBCC(AB_BOOL, cInt);

View File

@ -284,6 +284,8 @@ const char* GetC4VName(const C4V_Type Type)
return "nil";
case C4V_Int:
return "int";
case C4V_Float:
return "float";
case C4V_Bool:
return "bool";
case C4V_C4Object:
@ -309,6 +311,8 @@ char GetC4VID(const C4V_Type Type)
return 'A';
case C4V_Int:
return 'i';
case C4V_Float:
return 'f';
case C4V_Bool:
return 'b';
case C4V_C4Object:
@ -338,6 +342,8 @@ C4V_Type GetC4VFromID(const char C4VID)
return C4V_Any;
case 'i':
return C4V_Int;
case 'f':
return C4V_Float;
case 'b':
return C4V_Bool;
case 'o':
@ -400,9 +406,27 @@ bool C4Value::FnCnvObject(C4Value *Val, C4V_Type toType)
return false;
}
static bool FnI2F(C4Value *val, C4V_Type toType)
{
assert(val->GetType() == C4V_Int || val->GetType() == C4V_Bool);
assert(toType == C4V_Float);
val->SetFloat(val->_getInt());
return true;
}
static bool FnF2I(C4Value *val, C4V_Type toType)
{
assert(toType == C4V_Int || toType == C4V_Bool);
assert(val->GetType() == C4V_Float);
val->SetInt(val->_getFloat());
return val->ConvertTo(toType);
}
// Type conversion table
#define CnvOK 0, false // allow conversion by same value
#define CnvOK0 FnOk0, true
#define CnvI2F FnI2F, false // convert int->C4Real
#define CnvF2I FnF2I, false // convert C4Real->int
#define CnvError FnCnvError, true
#define CnvDeref FnCnvDeref, false
#define CnvPLR FnCnvPLR, false
@ -413,6 +437,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_Any - is always 0, convertible to everything
{ CnvOK }, // any same
{ CnvOK }, // int
{ CnvOK }, // float
{ CnvOK }, // Bool
{ CnvOK }, // PropList
{ CnvOK }, // C4Object
@ -424,6 +449,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_Int
{ CnvOK }, // any
{ CnvOK }, // int same
{ CnvI2F }, // float
{ CnvOK }, // Bool
{ CnvOK0 }, // PropList only if 0
{ CnvOK0 }, // C4Object only if 0
@ -432,9 +458,22 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ CnvError }, // Ref
{ CnvError }, // PropListRef
},
{ // C4V_Float
{ CnvOK }, // any
{ CnvF2I }, // int
{ CnvOK }, // float same
{ CnvF2I }, // Bool
{ CnvOK0 }, // PropList only if 0
{ CnvOK0 }, // C4Object only if 0
{ CnvOK0 }, // String only if 0
{ CnvOK0 }, // Array only if 0
{ CnvError }, // Ref
{ CnvError }, // PropListRef
},
{ // C4V_Bool
{ CnvOK }, // any
{ CnvOK }, // int might be used
{ CnvI2F }, // float
{ CnvOK }, // Bool same
{ CnvError }, // PropList NEVER!
{ CnvError }, // C4Object NEVER!
@ -446,6 +485,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_PropList
{ CnvOK }, // any
{ CnvError }, // int NEVER!
{ CnvError }, // float
{ CnvOK }, // Bool
{ CnvOK }, // PropList same
{ CnvObject }, // C4Object
@ -457,6 +497,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_Object
{ CnvOK }, // any
{ CnvError }, // int NEVER!
{ CnvError }, // float
{ CnvOK }, // Bool
{ CnvOK }, // PropList
{ CnvOK }, // C4Object same
@ -468,6 +509,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_String
{ CnvOK }, // any
{ CnvError }, // int NEVER!
{ CnvError }, // float
{ CnvOK }, // Bool
{ CnvError }, // PropList NEVER!
{ CnvError }, // C4Object NEVER!
@ -479,6 +521,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_Array
{ CnvOK }, // any
{ CnvError }, // int NEVER!
{ CnvError }, // float
{ CnvOK }, // Bool
{ CnvError }, // PropList NEVER!
{ CnvError }, // C4Object NEVER!
@ -490,6 +533,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_Ref - resolve reference and retry type check
{ CnvDeref }, // any
{ CnvDeref }, // int
{ CnvDeref }, // float
{ CnvDeref }, // Bool
{ CnvDeref }, // PropList
{ CnvDeref }, // C4Object
@ -501,6 +545,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_Ref - resolve reference and retry type check
{ CnvPLR }, // any
{ CnvPLR }, // int
{ CnvPLR }, // float
{ CnvPLR }, // Bool
{ CnvPLR }, // PropList
{ CnvPLR }, // C4Object
@ -513,6 +558,8 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
#undef CnvOK
#undef CnvOK0
#undef CnvI2F
#undef CnvF2I
#undef CnvError
#undef CnvDeref
#undef CnvPLR
@ -529,6 +576,8 @@ StdStrBuf C4Value::GetDataString()
{
case C4V_Int:
return FormatString("%ld", static_cast<long>(Data.Int));
case C4V_Float:
return FormatString("%f", static_cast<float>(C4Real(Data.Float)));
case C4V_Bool:
return StdStrBuf(Data ? "true" : "false");
case C4V_C4Object:
@ -671,6 +720,12 @@ void C4Value::CompileFunc(StdCompiler *pComp)
Data.Int = iTmp;
break;
case C4V_Float:
{
C4Real val = Data.Float;
pComp->Value(val);
Data.Float = val;
}
// object: save object number instead
case C4V_C4Object: case C4V_PropList:
@ -761,20 +816,25 @@ bool C4Value::operator == (const C4Value& Value2) const
assert(!Data);
return Value2.Type == Type;
case C4V_Int:
switch (Value2.Type)
{
case C4V_Int:
case C4V_Bool:
return Data == Value2.Data;
default:
return false;
}
case C4V_Bool:
switch (Value2.Type)
{
case C4V_Int:
case C4V_Bool:
return Data == Value2.Data;
case C4V_Float:
return C4Real(Value2.Data.Float) == static_cast<int>(Data.Int);
default:
return false;
}
case C4V_Float:
switch (Value2.Type)
{
case C4V_Int:
case C4V_Bool:
return C4Real(Data.Float) == static_cast<int>(Data.Int);
case C4V_Float:
return Data.Float == Value2.Data.Float;
default:
return false;
}

View File

@ -21,6 +21,7 @@
#define INC_C4Value
#include "C4Id.h"
#include "C4Real.h"
// class declarations
class C4Value;
@ -32,18 +33,19 @@ class C4ValueArray;
// C4Value type
enum C4V_Type
{
C4V_Any=0, // nil
C4V_Int=1,
C4V_Bool=2,
C4V_PropList=3,
C4V_C4Object=4,
C4V_String=5,
C4V_Array=6,
C4V_Ref=7, // reference to a value (variable)
C4V_PropListRef=8, // reference to an entry in a proplist
C4V_Any, // nil
C4V_Int,
C4V_Float,
C4V_Bool,
C4V_PropList,
C4V_C4Object,
C4V_String,
C4V_Array,
C4V_Ref, // reference to a value (variable)
C4V_PropListRef, // reference to an entry in a proplist
C4V_C4ObjectEnum=9, // enumerated object
C4V_C4DefEnum=10 // enumerated object
C4V_C4ObjectEnum, // enumerated object
C4V_C4DefEnum // enumerated object
};
#define C4V_Last (int) C4V_PropListRef
@ -54,6 +56,7 @@ C4V_Type GetC4VFromID(char C4VID);
union C4V_Data
{
C4Real::StorageType Float;
intptr_t Int;
C4Object * Obj;
C4PropList * PropList;
@ -88,6 +91,8 @@ public:
{ Data.Int = data; AddDataRef(); }
explicit C4Value(int32_t data): NextRef(NULL), FirstRef(NULL), Type(C4V_Int), HasBaseArray(false)
{ Data.Int = data; AddDataRef(); }
explicit C4Value(C4Real data): NextRef(NULL), FirstRef(NULL), Type(C4V_Float), HasBaseArray(false)
{ Data.Float = data; AddDataRef(); }
explicit C4Value(C4Object *pObj): NextRef(NULL), FirstRef(NULL), Type(pObj ? C4V_C4Object : C4V_Any), HasBaseArray(false)
{ Data.Obj = pObj; AddDataRef(); }
explicit C4Value(C4String *pStr): NextRef(NULL), FirstRef(NULL), Type(pStr ? C4V_String : C4V_Any), HasBaseArray(false)
@ -105,6 +110,7 @@ public:
// Checked getters
int32_t getInt() { return ConvertTo(C4V_Int) ? Data.Int : 0; }
C4Real getFloat() { return ConvertTo(C4V_Float) ? Data.Float : C4Real(0); }
bool getBool() { return ConvertTo(C4V_Bool) ? !! Data : 0; }
C4ID getC4ID();
C4Object * getObj() { return ConvertTo(C4V_C4Object) ? Data.Obj : NULL; }
@ -115,6 +121,7 @@ public:
// Unchecked getters
int32_t _getInt() const { return Data.Int; }
C4Real _getFloat() const { return Data.Float; }
bool _getBool() const { return !! Data.Int; }
C4Object *_getObj() const { return Data.Obj; }
C4String *_getStr() const { return Data.Str; }
@ -133,6 +140,8 @@ public:
void SetInt(int i) { C4V_Data d; d.Int = i; Set(d, C4V_Int); }
void SetFloat(C4Real f) { C4V_Data d; d.Float = f; Set(d, C4V_Float); }
void SetBool(bool b) { C4V_Data d; d.Int = b; Set(d, C4V_Bool); }
void SetObject(C4Object * Obj) { C4V_Data d; d.Obj = Obj; Set(d, C4V_C4Object); }
@ -153,10 +162,29 @@ public:
bool operator != (const C4Value& Value2) const;
// Change and set Type to int in case it was any before (avoids GuessType())
C4Value & operator += (int32_t by) { GetData().Int += by; GetRefVal().Type=C4V_Int; return *this; }
C4Value & operator -= (int32_t by) { GetData().Int -= by; GetRefVal().Type=C4V_Int; return *this; }
C4Value & operator *= (int32_t by) { GetData().Int *= by; GetRefVal().Type=C4V_Int; return *this; }
C4Value & operator /= (int32_t by) { GetData().Int /= by; GetRefVal().Type=C4V_Int; return *this; }
#define C4VALUE_ARITHMETIC_OPERATOR(op) \
/* combined arithmetic and assignment op */ \
C4Value &operator op##= (const C4Value &rhs) \
{ \
/* Promote numeric values to float if any operand is float */ \
if (rhs.GetType() == C4V_Float || GetType() == C4V_Float) \
{ \
C4Real lhsf = getFloat(); \
C4Real rhsf = C4Value(rhs).getFloat(); \
SetFloat(lhsf op##= rhsf); \
} \
else \
{ \
GetData().Int op##= rhs.GetData().Int; \
GetRefVal().Type=C4V_Int; \
} \
return *this; \
}
C4VALUE_ARITHMETIC_OPERATOR(+)
C4VALUE_ARITHMETIC_OPERATOR(-)
C4VALUE_ARITHMETIC_OPERATOR(*)
C4VALUE_ARITHMETIC_OPERATOR(/)
#undef C4VALUE_ARITHMETIC_OPERATOR
C4Value & operator %= (int32_t by) { GetData().Int %= by; GetRefVal().Type=C4V_Int; return *this; }
C4Value & operator &= (int32_t by) { GetData().Int &= by; GetRefVal().Type=C4V_Int; return *this; }
C4Value & operator ^= (int32_t by) { GetData().Int ^= by; GetRefVal().Type=C4V_Int; return *this; }
@ -215,7 +243,7 @@ public:
void CompileFunc(StdCompiler *pComp);
static inline bool IsNullableType(C4V_Type Type)
{ return Type == C4V_Int || Type == C4V_Bool; }
{ return Type == C4V_Int || Type == C4V_Float || Type == C4V_Bool; }
protected:
// data
@ -269,6 +297,7 @@ protected:
// converter
inline C4Value C4VInt(int32_t iVal) { C4V_Data d; d.Int = iVal; return C4Value(d, C4V_Int); }
inline C4Value C4VFloat(C4Real f) { return C4Value(f); }
inline C4Value C4VBool(bool fVal) { C4V_Data d; d.Int = fVal; return C4Value(d, C4V_Bool); }
C4Value C4VID(C4ID iVal);
inline C4Value C4VObj(C4Object *pObj) { return C4Value(pObj); }
@ -288,6 +317,13 @@ template <> struct C4ValueConv<int32_t>
inline static int32_t _FromC4V(C4Value &v) { return v._getInt(); }
inline static C4Value ToC4V(int32_t v) { return C4VInt(v); }
};
template <> struct C4ValueConv<C4Real>
{
inline static C4V_Type Type() { return C4V_Float; }
inline static C4Real FromC4V(C4Value &v) { return v.getFloat(); }
inline static C4Real _FromC4V(C4Value &v) { return v._getFloat(); }
inline static C4Value ToC4V(C4Real v) { return C4VFloat(v); }
};
template <> struct C4ValueConv<bool>
{
inline static C4V_Type Type() { return C4V_Bool; }