#include "math64.h"

#ifndef COMPILER_SUPPORTS_LONG_LONG



UInt64 u64_from_halves(UInt32 hi, UInt32 lo){
	
	UInt64 r;
	
	r.lo = lo;
	r.hi = hi;
	
	return r;	
}


UInt64 u64_32_to_64(UInt32 v){
	
	UInt64 r;
	
	r.hi = 0;
	r.lo = v;
	
	return r;	
}

UInt32 u64_64_to_32(UInt64 v){
	
	return v.lo;	
}

UInt32 u64_get_hi(UInt64 v){
	
	return v.hi;	
}

UInt64 u64_add(UInt64 a, UInt64 b){
	
	UInt64 r;
	
	r.lo = a.lo + b.lo;
	r.hi = a.hi + b.hi;
	if(r.lo < a.lo) r.hi++;
	
	return r;
}

UInt64 u64_add32(UInt64 a, UInt32 b){
	
	UInt64 r;
	
	r.lo = a.lo + b;
	r.hi = a.hi;
	if(r.lo < a.lo) r.hi++;
	
	return r;	
}

UInt64 u64_umul3232(UInt32 a, UInt32 b){
	
	UInt64 r;
	UInt32 ah, al, bh, bl;
	
	ah = a >> 16;
	al = a & 0xFFFFUL;
	bh = b >> 16;
	bl = b & 0xFFFFUL;
	
	r = u64_shl(u64_32_to_64(ah * bh), 16);
	r = u64_add32(r, ah * bl);
	r = u64_add32(r, al * bh);
	r = u64_add32(u64_shl(r, 16), al * bl);
	
	return r;
}

UInt64 u64_smul3232(Int32 a, Int32 b){
	
	Boolean negative = false;
	UInt64 r;
	
	if(a < 0){
		a = -a;
		negative = !negative;
	}
	
	if(b < 0){
		b = -b;
		negative = !negative;
	}
	
	r = u64_umul3232(a, b);
	
	if(negative){
		
		r.hi = ~r.hi;			//negate r
		r.lo = ~r.lo;
		r = u64_inc(r);
	}
	
	return r;
}

UInt64 u64_shr(UInt64 v, unsigned bits){
	
	UInt64 a = v;
	
	while(bits >= 32){
		a.lo = a.hi;
		a.hi = 0;
		bits -= 32;
	}
	
	a.lo = (a.lo >> bits) + (a.hi << (32 - bits));
	a.hi >>= bits;
	
	return a;
}

UInt64 u64_shl(UInt64 v, unsigned bits){
	
	UInt64 a = v;
	
	while(bits >= 32){
		a.hi = a.lo;
		a.lo = 0;
		bits -= 32;
	}
	
	a.hi = (a.hi << bits) + (a.lo >> (32 - bits));
	a.lo <<= bits;
	
	return a;
}

UInt64 u64_xtnd32(UInt64 v){
	
	UInt64 a = v;
	
	if(a.lo & 0x80000000UL) a.hi = 0xFFFFFFFFUL;
	
	return a;
}

Boolean u64_isZero(UInt64 a){
	
	return a.lo == 0 && a.hi == 0;
}

UInt64 u64_inc(UInt64 v){
	
	UInt64 a = v;
	
	if(!++a.lo) a.hi++;
	
	return a;
}

UInt64 u64_and(UInt64 a, UInt64 b){
	
	UInt64 r;
	
	r.lo = a.lo & b.lo;
	r.hi = a.hi & b.hi;
	
	return r;	
}

UInt64 u64_zero(void){
	
	UInt64 r;
	
	r.lo = 0;
	r.hi = 0;
	
	return r;	
}


UInt64 u64_sub(UInt64 a, UInt64 b){
	
	UInt64 bn;
	
	bn.lo = ~b.lo;
	bn.hi = ~b.hi;
	
	bn = u64_inc(bn);
	
	return u64_add(a, bn);
}





#endif