/* xyz */

/*
 * Copyright (c) 1996-2005 by Wayne C. Gramlich.
 * All rights reserved.
 */

/*
 * This file implements the float base type operations in ANSI-C.
 */

#ifndef ERROR_EXPORTS_H
#include "error_exports.h"
#endif

#ifndef STHEADERS_H
#include "stheaders.h"
#endif

#ifndef UNIX_ASSERT_H
#include "unix_assert.h"
#endif

#include <math.h>

#define POWER 10
#define SIZE (1<<POWER)
#define MASK (SIZE - 1)
#define RESULT() (buffer[(++buffer_index) & MASK])

typedef int Float;		/* Definition copied from float_c.c */
typedef double *Real;

/* A circular buffer of intermediate results. */
static unsigned buffer_index = 0;
static Real buffer[SIZE];

static double real__one_value = 1.0;
Real real__one = &real__one_value;

static double real__zero_value = 0.0;
Real real__zero = &real__zero_value;

static double real___initial_value = 0.0;
Real real___initial = &real___initial_value;

extern module___object real__module__object;
extern type___reference real_type_ref;

static object___object real_initial_object = {
	"",				/* Package name */
	"real",				/* Type name */
	"??",				/* Object name */
	(type___reference *)0,		/*XXX: Fix me */
	(int *)0,			/* Size of float object */
	0,				/* Static needs count */
	(need___entry *)0,		/*XXX: Fix me Static needs */
	0,				/* Parameter needs count */
	(need___entry *)0,		/* Parameter needs */
	(void **)&real___initial,	/* Object pointer */
	(instantiation___object *)0	/* Instantiation list */
};
static object___object *object_list[1] = {
	&real_initial_object,
};

Real real__allocate(void);

void
real__external__initialize(void)
{
	unsigned	index;

	for (index = 0; index < SIZE; index++) {
		buffer[index] = real__allocate();
	}
	real__module__object.object_count = 1;
	real__module__object.objects = object_list;
}

Real
real__add(
	Real	left,
	Real	right)
{
	Real	result = RESULT();

	*result = *left + *right;
	return result;
}

Real
real__copy(
	   Real	arg)
{
	Real	result;

	result = (Real)memory_allocate(sizeof(double));

	*result = *arg;
	return result;
}

Real
real__cosine(
	Real	angle)
{
	Real	result = RESULT();

	*result = cos(*angle);
	return result;
}

Real
real__divide(
	Real	left,
	Real	right)
{
	Real	result = RESULT();

	*result = *left / *right;
	return result;
}

int
real__equal(
	Real	left,
	Real	right)
{
	return *left == *right;
}

Float
real__float_convert(
	Real	real)
{
	/*
	 * The only way to really ensure that the bits are stuffed
	 * into 32-bits is to use a structure.
	 */
	struct {
		float	f;
	} fl;

	fl.f = (float)(*real);
	return *((Float *)&fl.f);
}

Real
real__float_to_real(
	Float	fl)
{
	Real	result = RESULT();
	float	f = *((float *)&fl);

	*result = (double)f;
	return result;
}

int
real__greater_than(
	Real	left,
	Real	right)
{
	return *left > *right;
}

unsigned
real__hash(
	long long *arg)
{
	long long value = *arg;

	return (value & 0xffffffff) ^ (value >> 32);
}

int
real__less_than(
	Real	left,
	Real	right)
{
	return *left < *right;
}

Real
real__minus(
	Real	arg)
{
	Real	result = RESULT();

	*result = -*arg;
	return result;
}

Real
real__multiply(
	Real	left,
	Real	right)
{
	Real	result = RESULT();

	*result = *left * *right;
	return result;

}

Real
real__allocate(void)
{
	Real	result = (Real)memory_allocate(sizeof(double));

	*result = 0.0;
	return result;
}

Real
real__power(
	Real	left,
	Real	right)
{
	Real	result = RESULT();

	*result = pow(*left, *right);
	return result;
}

Real
real__remainder(
	Real	left,
	Real	right)
{
	Real	result = RESULT();

	assert(0);
	/* *result = *left % *right; */
	return result;
}

void
real__set_set(
	Real	left,
	Real	right)
{
	*left = *right;
}

Real
real__sine(
	Real	angle)
{
	Real	result = RESULT();

	*result = sin(*angle);
	return result;
}

Real
real__square_root(
	Real	arg)
{
	Real	result = RESULT();

	*result = sqrt(*arg);
	return result;
}

Real
real__subtract(
	Real	left,
	Real	right)
{
	Real	result = RESULT();

	*result = *left - *right;
	return result;
}

unsigned
real__unsigned_convert(
	Real	arg)
{
	return (unsigned)rint(*arg);
}

Real
unsigned__real_convert(
	unsigned	arg)
{
	Real	result = RESULT();

	*result = (double)arg;
	return result;
}
