/************************************************************************
 ************************************************************************
    FAUST compiler
	Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
    ---------------------------------------------------------------------
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 ************************************************************************
 ************************************************************************/
 
 
 
/*****************************************************************************
******************************************************************************
								NUM 
						Y. Orlarey, (c) Grame 2002
------------------------------------------------------------------------------
Nums are tagged unions of ints and floats. Nums are completly described by 
the num.h file, there is no num.cpp file.

 API:
 ----
	num(10);				: num with int content
	num(3.14159);			: num with double content
	
	num op num				: op is any C binary operator
	
	type(num)				: 0 = int, 1 = double
	int(num);				: int content of num or conversion
	double(num);				: double content of num or conversion
	
 History :
 ---------
 	2002-02-08 : First version
	
******************************************************************************
*****************************************************************************/


#ifndef     __NUM__
#define     __NUM__


//-------------------------------------------------------------------------
// Class num = (int x (int + double))
//-------------------------------------------------------------------------
class num
{
	int		fType;
	union { 
		int 	i; 
		double 	f;
	} fData;

 public:
	// constructeurs
	num (int x=0) 		: fType(0) 			{ fData.i = x; }
	//num (double x) 		: fType(1)  		{ fData.f = (double)x; }
	num (double x) 		: fType(1)  		{ fData.f = x; }
	num (const num& n) 	: fType(n.fType) 	{ fData.i = n.fData.i; }

	num& operator = (int n) 	{ fType = 0; fData.i = n; return *this; }
	num& operator = (double n) 	{ fType = 1; fData.f = n; return *this; }
 	
	// predicats
	bool operator == (const num& n) const { return fType == n.fType && fData.i == n.fData.i; }
	bool operator != (const num& n) const { return fType != n.fType || fData.i != n.fData.i; }
	
	// accessors
	int			type() 		const 	{ return fType; }
	operator 	int() 		const 	{ return (fType) ? int(fData.f) : fData.i; }
	operator 	double() 	const 	{ return (fType) ? fData.f : double(fData.i); }
	
};


inline int isfloat (const num& n) { return n.type(); }

inline const num operator+ (const num& x, const num& y)	
	{ return (isfloat(x)|isfloat(y)) ? num(double(x)+double(y)) : num(int(x)+int(y)); }

inline const num operator- (const num& x, const num& y)	
	{ return (isfloat(x)|isfloat(y)) ? num(double(x)-double(y)) : num(int(x)-int(y)); }

inline const num operator* (const num& x, const num& y)	
	{ return (isfloat(x)|isfloat(y)) ? num(double(x)*double(y)) : num(int(x)*int(y)); }

inline const num operator/ (const num& x, const num& y)	
	{ return (isfloat(x)|isfloat(y)) ? num(double(x)/double(y)) : num(int(x)/int(y)); }

inline const num operator% (const num& x, const num& y)	
	{ return num(int(x)%int(y)); }


// operations sur les bits
inline const num operator<< (const num& x, const num& y)	
	{ return num(int(x)<<int(y)); }

inline const num operator>> (const num& x, const num& y)	
	{ return num(int(x)>>int(y)); }


// operations booléennes sur les bits
inline const num operator& (const num& x, const num& y)	
	{ return num(int(x)&int(y)); }

inline const num operator| (const num& x, const num& y)	
	{ return num(int(x)|int(y)); }

inline const num operator^ (const num& x, const num& y)	
	{ return num(int(x)^int(y)); }


// operations de comparaison
inline const num operator> (const num& x, const num& y)	
	{ return (isfloat(x)|isfloat(y)) ? num(double(x)>double(y)) : num(int(x)>int(y)); }

inline const num operator< (const num& x, const num& y)	
	{ return (isfloat(x)|isfloat(y)) ? num(double(x)<double(y)) : num(int(x)<int(y)); }

inline const num operator>= (const num& x, const num& y)	
	{ return (isfloat(x)|isfloat(y)) ? num(double(x)>=double(y)) : num(int(x)>=int(y)); }

inline const num operator<= (const num& x, const num& y)	
	{ return (isfloat(x)|isfloat(y)) ? num(double(x)<=double(y)) : num(int(x)<=int(y)); }

inline const num operator== (const num& x, const num& y)	
	{ return (isfloat(x)|isfloat(y)) ? num(double(x)==double(y)) : num(int(x)==int(y)); }

inline const num operator!= (const num& x, const num& y)	
	{ return (isfloat(x)|isfloat(y)) ? num(double(x)!=double(y)) : num(int(x)!=int(y)); }


#endif    
