summaryrefslogtreecommitdiffstats
path: root/gnu/lib/libg++/include/Fix.h
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/lib/libg++/include/Fix.h')
-rw-r--r--gnu/lib/libg++/include/Fix.h513
1 files changed, 513 insertions, 0 deletions
diff --git a/gnu/lib/libg++/include/Fix.h b/gnu/lib/libg++/include/Fix.h
new file mode 100644
index 0000000..df76c94
--- /dev/null
+++ b/gnu/lib/libg++/include/Fix.h
@@ -0,0 +1,513 @@
+// -*- C++ -*-
+// Fix.h : variable length fixed point data type
+//
+
+#ifndef _Fix_h
+#ifdef __GNUG__
+#pragma interface
+#endif
+#define _Fix_h 1
+
+#include <stream.h>
+#include <std.h>
+#include <stddef.h>
+#include <Integer.h>
+#include <builtin.h>
+
+class Fix
+{
+ struct Rep // internal Fix representation
+ {
+ _G_uint16_t len; // length in bits
+ _G_uint16_t siz; // allocated storage
+ _G_int16_t ref; // reference count
+ _G_uint16_t s[1]; // start of ushort array represention
+ };
+
+public:
+
+ typedef void (*PEH)(Rep*);
+
+private:
+
+ Rep* rep;
+
+ Fix(Rep*);
+ Fix(int, const Rep*);
+
+ void unique();
+
+ static const _G_uint16_t min_length = 1;
+ static const _G_uint16_t max_length = 65535;
+ static const double min_value = -1.0;
+ static const double max_value = 1.0;
+
+ static _G_uint16_t default_length;
+ static int default_print_width;
+ static Rep Rep_0;
+ static Rep Rep_m1;
+ static Rep Rep_quotient_bump;
+
+ // internal class functions
+ static void mask(Rep*);
+ static int compare(const Rep*, const Rep* = &Rep_0);
+
+ static Rep* new_Fix(_G_uint16_t);
+ static Rep* new_Fix(_G_uint16_t, const Rep*);
+ static Rep* new_Fix(_G_uint16_t, double);
+
+ static Rep* copy(const Rep*, Rep*);
+ static Rep* negate(const Rep*, Rep* = NULL);
+ static Rep* add(const Rep*, const Rep*, Rep* = NULL);
+ static Rep* subtract(const Rep*, const Rep*, Rep* = NULL);
+ static Rep* multiply(const Rep*, const Rep*, Rep* = NULL);
+ static Rep* multiply(const Rep*, int, Rep* = NULL);
+ static Rep* divide(const Rep*, const Rep*, Rep* = NULL,
+ Rep* = NULL);
+ static Rep* shift(const Rep*, int, Rep* = NULL);
+
+ static one_arg_error_handler_t error_handler;
+ static one_arg_error_handler_t range_error_handler;
+
+ static PEH overflow_handler;
+
+public:
+ Fix();
+ Fix(const Fix&);
+ Fix(double);
+ Fix(int);
+ Fix(int, const Fix&);
+ Fix(int, double);
+
+ ~Fix();
+
+ Fix operator = (const Fix&);
+ Fix operator = (double);
+
+ friend int operator == (const Fix&, const Fix&);
+ friend int operator != (const Fix&, const Fix&);
+
+ friend int operator < (const Fix&, const Fix&);
+ friend int operator <= (const Fix&, const Fix&);
+ friend int operator > (const Fix&, const Fix&);
+ friend int operator >= (const Fix&, const Fix&);
+
+ Fix& operator + ();
+ Fix operator - ();
+
+ friend Fix operator + (const Fix&, const Fix&);
+ friend Fix operator - (const Fix&, const Fix&);
+ friend Fix operator * (const Fix&, const Fix&);
+ friend Fix operator / (const Fix&, const Fix&);
+
+ friend Fix operator * (const Fix&, int);
+ friend Fix operator * (int, const Fix&);
+ friend Fix operator % (const Fix&, int);
+ friend Fix operator << (const Fix&, int);
+ friend Fix operator >> (const Fix&, int);
+
+#if defined (__GNUG__) && ! defined (__STRICT_ANSI__)
+ friend Fix operator <? (const Fix&, const Fix&); // min
+ friend Fix operator >? (const Fix&, const Fix&); // max
+#endif
+
+ Fix operator += (const Fix&);
+ Fix operator -= (const Fix&);
+ Fix operator *= (const Fix&);
+ Fix operator /= (const Fix&);
+
+ Fix operator *= (int);
+ Fix operator %= (int);
+ Fix operator <<=(int);
+ Fix operator >>=(int);
+
+ friend char* Ftoa(const Fix&, int width = default_print_width);
+ void printon(ostream&, int width = default_print_width) const;
+ friend Fix atoF(const char*, int len = default_length);
+
+ friend istream& operator >> (istream&, Fix&);
+ friend ostream& operator << (ostream&, const Fix&);
+
+ // built-in functions
+ friend Fix abs(Fix); // absolute value
+ friend int sgn(const Fix&); // -1, 0, +1
+ friend Integer mantissa(const Fix&); // integer representation
+ friend double value(const Fix&); // double value
+ friend int length(const Fix&); // field length
+ friend void show(const Fix&); // show contents
+
+ // error handlers
+ static void error(const char* msg); // error handler
+ static void range_error(const char* msg); // range error handler
+
+ static one_arg_error_handler_t set_error_handler(one_arg_error_handler_t f);
+ static one_arg_error_handler_t
+ set_range_error_handler(one_arg_error_handler_t f);
+
+ static void default_error_handler (const char *);
+ static void default_range_error_handler (const char *);
+
+ // non-operator versions for user
+ friend void negate(const Fix& x, Fix& r);
+ friend void add(const Fix& x, const Fix& y, Fix& r);
+ friend void subtract(const Fix& x, const Fix& y, Fix& r);
+ friend void multiply(const Fix& x, const Fix& y, Fix& r);
+ friend void divide(const Fix& x, const Fix& y, Fix& q, Fix& r);
+ friend void shift(const Fix& x, int y, Fix& r);
+
+ // overflow handlers
+ static void overflow_saturate(Fix::Rep*);
+ static void overflow_wrap(Fix::Rep*);
+ static void overflow_warning_saturate(Fix::Rep*);
+ static void overflow_warning(Fix::Rep*);
+ static void overflow_error(Fix::Rep*);
+
+ static PEH set_overflow_handler(PEH);
+
+ static int set_default_length(int);
+};
+
+// function definitions
+
+inline void
+Fix::unique()
+{
+ if ( rep->ref > 1 )
+ {
+ rep->ref--;
+ rep = new_Fix(rep->len,rep);
+ }
+}
+
+inline void
+Fix::mask (Fix::Rep* x)
+{
+ int n = x->len & 0x0f;
+ if ( n )
+ x->s[x->siz - 1] &= 0xffff0000 >> n;
+}
+
+inline Fix::Rep*
+Fix::copy(const Fix::Rep* from, Fix::Rep* to)
+{
+ _G_uint16_t *ts = to->s;
+ const _G_uint16_t *fs = from->s;
+ int ilim = to->siz < from->siz ? to->siz : from->siz;
+ for ( int i=0; i < ilim; i++ )
+ *ts++ = *fs++;
+ for ( ; i < to->siz; i++ )
+ *ts++ = 0;
+ mask(to);
+ return to;
+}
+
+inline
+Fix::Fix(Rep* f)
+{
+ rep = f;
+}
+
+inline
+Fix::Fix()
+{
+ rep = new_Fix(default_length);
+}
+
+inline
+Fix::Fix(int len)
+{
+ if ( len < min_length || len > max_length )
+ error("illegal length in declaration");
+ rep = new_Fix((_G_uint16_t) len);
+}
+
+inline
+Fix::Fix(double d)
+{
+ rep = new_Fix(default_length,d);
+}
+
+inline
+Fix::Fix(const Fix& y)
+{
+ rep = y.rep; rep->ref++;
+}
+
+inline
+Fix::Fix(int len, const Fix& y)
+{
+ if ( len < Fix::min_length || len > Fix::max_length )
+ error("illegal length in declaration");
+ rep = new_Fix((_G_uint16_t) len,y.rep);
+}
+
+inline
+Fix::Fix(int len, const Rep* fr)
+{
+ if ( len < Fix::min_length || len > Fix::max_length )
+ error("illegal length in declaration");
+ rep = new_Fix((_G_uint16_t) len,fr);
+}
+
+inline
+Fix::Fix(int len, double d)
+{
+ if ( len < Fix::min_length || len > Fix::max_length )
+ error("illegal length in declaration");
+ rep = new_Fix((_G_uint16_t) len,d);
+}
+
+inline
+Fix::~Fix()
+{
+ if ( --rep->ref <= 0 ) delete rep;
+}
+
+inline Fix
+Fix::operator = (const Fix& y)
+{
+ if ( rep->len == y.rep->len ) {
+ ++y.rep->ref;
+ if ( --rep->ref <= 0 ) delete rep;
+ rep = y.rep;
+ }
+ else {
+ unique();
+ copy(y.rep,rep);
+ }
+ return *this;
+}
+
+inline Fix
+Fix::operator = (double d)
+{
+ int oldlen = rep->len;
+ if ( --rep->ref <= 0 ) delete rep;
+ rep = new_Fix(oldlen,d);
+ return *this;
+}
+
+inline int
+operator == (const Fix& x, const Fix& y)
+{
+ return Fix::compare(x.rep, y.rep) == 0;
+}
+
+inline int
+operator != (const Fix& x, const Fix& y)
+{
+ return Fix::compare(x.rep, y.rep) != 0;
+}
+
+inline int
+operator < (const Fix& x, const Fix& y)
+{
+ return Fix::compare(x.rep, y.rep) < 0;
+}
+
+inline int
+operator <= (const Fix& x, const Fix& y)
+{
+ return Fix::compare(x.rep, y.rep) <= 0;
+}
+
+inline int
+operator > (const Fix& x, const Fix& y)
+{
+ return Fix::compare(x.rep, y.rep) > 0;
+}
+
+inline int
+operator >= (const Fix& x, const Fix& y)
+{
+ return Fix::compare(x.rep, y.rep) >= 0;
+}
+
+inline Fix&
+Fix::operator + ()
+{
+ return *this;
+}
+
+inline Fix
+Fix::operator - ()
+{
+ Rep* r = negate(rep); return r;
+}
+
+inline Fix
+operator + (const Fix& x, const Fix& y)
+{
+ Fix::Rep* r = Fix::add(x.rep, y.rep); return r;
+}
+
+inline Fix
+operator - (const Fix& x, const Fix& y)
+{
+ Fix::Rep* r = Fix::subtract(x.rep, y.rep); return r;
+}
+
+inline Fix
+operator * (const Fix& x, const Fix& y)
+{
+ Fix::Rep* r = Fix::multiply(x.rep, y.rep); return r;
+}
+
+inline Fix
+operator * (const Fix& x, int y)
+{
+ Fix::Rep* r = Fix::multiply(x.rep, y); return r;
+}
+
+inline Fix
+operator * (int y, const Fix& x)
+{
+ Fix::Rep* r = Fix::multiply(x.rep, y); return r;
+}
+
+inline Fix
+operator / (const Fix& x, const Fix& y)
+{
+ Fix::Rep* r = Fix::divide(x.rep, y.rep); return r;
+}
+
+inline Fix
+Fix::operator += (const Fix& y)
+{
+ unique(); Fix::add(rep, y.rep, rep); return *this;
+}
+
+inline Fix
+Fix::operator -= (const Fix& y)
+{
+ unique(); Fix::subtract(rep, y.rep, rep); return *this;
+}
+
+inline Fix
+Fix::operator *= (const Fix& y)
+{
+ unique(); Fix::multiply(rep, y.rep, rep); return *this;
+}
+
+inline Fix
+Fix::operator *= (int y)
+{
+ unique(); Fix::multiply(rep, y, rep); return *this;
+}
+
+inline Fix
+Fix::operator /= (const Fix& y)
+{
+ unique(); Fix::divide(rep, y.rep, rep); return *this;
+}
+
+inline Fix
+operator % (const Fix& x, int y)
+{
+ Fix r((int) x.rep->len + y, x); return r;
+}
+
+inline Fix
+operator << (const Fix& x, int y)
+{
+ Fix::Rep* rep = Fix::shift(x.rep, y); return rep;
+}
+
+inline Fix
+operator >> (const Fix& x, int y)
+{
+ Fix::Rep* rep = Fix::shift(x.rep, -y); return rep;
+}
+
+inline Fix
+Fix::operator <<= (int y)
+{
+ unique(); Fix::shift(rep, y, rep); return *this;
+}
+
+inline Fix
+Fix::operator >>= (int y)
+{
+ unique(); Fix::shift(rep, -y, rep); return *this;
+}
+
+#if defined (__GNUG__) && ! defined (__STRICT_ANSI__)
+inline Fix
+operator <? (const Fix& x, const Fix& y)
+{
+ if ( Fix::compare(x.rep, y.rep) <= 0 ) return x; else return y;
+}
+
+inline Fix
+operator >? (const Fix& x, const Fix& y)
+{
+ if ( Fix::compare(x.rep, y.rep) >= 0 ) return x; else return y;
+}
+#endif
+
+inline Fix
+abs(Fix x)
+{
+ Fix::Rep* r = (Fix::compare(x.rep) >= 0 ? Fix::new_Fix(x.rep->len,x.rep) :
+ Fix::negate(x.rep));
+ return r;
+}
+
+inline int
+sgn(const Fix& x)
+{
+ int a = Fix::compare(x.rep);
+ return a == 0 ? 0 : (a > 0 ? 1 : -1);
+}
+
+inline int
+length(const Fix& x)
+{
+ return x.rep->len;
+}
+
+inline ostream&
+operator << (ostream& s, const Fix& y)
+{
+ if (s.opfx())
+ y.printon(s);
+ return s;
+}
+
+inline void
+negate (const Fix& x, Fix& r)
+{
+ Fix::negate(x.rep, r.rep);
+}
+
+inline void
+add (const Fix& x, const Fix& y, Fix& r)
+{
+ Fix::add(x.rep, y.rep, r.rep);
+}
+
+inline void
+subtract (const Fix& x, const Fix& y, Fix& r)
+{
+ Fix::subtract(x.rep, y.rep, r.rep);
+}
+
+inline void
+multiply (const Fix& x, const Fix& y, Fix& r)
+{
+ Fix::multiply(x.rep, y.rep, r.rep);
+}
+
+inline void
+divide (const Fix& x, const Fix& y, Fix& q, Fix& r)
+{
+ Fix::divide(x.rep, y.rep, q.rep, r.rep);
+}
+
+inline void
+shift (const Fix& x, int y, Fix& r)
+{
+ Fix::shift(x.rep, y, r.rep);
+}
+
+#endif
OpenPOWER on IntegriCloud