[AD] a fix struct for dallegro

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


I don't know how useful this is. It was done in part to see how different from the C++ version it would be. It's based on allegro's C++ fix class. But it sure simplifies fixed point calculations when you need them. Most of the my current implementation is attached. Most of the actual fix.d file is comprised of the unit test, which isn't complete yet. I can post the rest of the implementation when it's cleaned up a bit.

I'm looking for feedback about the interface of the fix struct. Let me know what you think. Note that it's a struct, not a class. D classes are reference types with two data words of fixed overhead (a vptr and a monitor for syncing). Structs are just data, but they can have non-virtual methods and operator overloads.


A simple example:
---
import allegro.fix;

void main() {
   fix a = 5;

   a /= 2;  // b becomes 2.5

   writefln(a + 3)  // calls toString(), prints 5.5
}

---

Since there are no user-defined implicit conversions in D, conversions to other types are explicit:

fix a = 3.7;
long b = a.toInt();
float c = a.toDouble();
char[] d = a.toString();


You can access the fixed value directly, through a property. I've named it 'f', to remind users that it is of type fixed. There might be a better way to do this, suggestions are welcome.

allegro_function_taking_a_fixed_as_arg(fix(-3.5).f);
fix a.f = allegro_function_returning_a_fixed();

Since fixed is just an alias for int, there's still the danger of mixing fixed and int values. So this solution isn't perfect. I tried making fixed a D typedef, which would make it a completely distinct type from int. But that requires a lot of casting when using it. Another option is to replace fixed by the fix struct, which requires a lot of changes to allegro's fixed point conversion and arithmetics functions. Maybe I'll look into it.
struct fix
{
   static assert(fix.sizeof == 4);  // revise code if size changes

   union  {
      private fixed value = 0;
      private fixed v;  // shorter alias for 'value'
   }

   fixed f() { return value; }
   fixed f(fixed)  { value = f; }  // FIXME: validate value?

   /// Acts as a conversion constructor.
   static fix opCall(int x)
   {
      fix f = void;
      f.value = itofix(x);
      return f;
   }

   static fix opCall(long x) { return opCall(cast(int)x); }  /// ditto

   static fix opCall(double x)  /// ditto
   {
      fix f = void;
      f.value = ftofix(x);
      return f;
   }


   int toInt() { return fixtoi(value); }
   double toDouble() { return fixtof(value); }

   /// Convert to a string, good for debugging etc.
   toString() {  /* implementation too long to include */ }
   alias toString toUtf8;  // Tango uses toUtf8 instead

   fix opAssign(int x) { value = itofix(x); return *this; }
   fix opAssign(long x) { return opAssign(cast(int)x); }
   fix opAssign(double x) { value = ftofix(x); return *this; }

   fix opAddAssign(fix x)           { value += x.value;      return *this; }
   fix opAddAssign(int x)           { value += itofix(x);    return *this; }
   fix opAddAssign(long x)          { return opAddAssign(cast(int)x); }
   fix opAddAssign(double x)        { value += ftofix(x);    return *this; }

   fix opSubAssign(fix x)        { value -= x.value;            return *this; }
   fix opSubAssign(int x)        { value -= itofix(x);          return *this; }
   fix opSubAssign(long x)       { value -= itofix(cast(int)x); return *this; }
   fix opSubAssign(double x)     { value -= ftofix(x);          return *this; }

   fix opMulAssign(fix x)     { value = fixmul(value, x.value); return *this; }
   fix opMulAssign(int x)     { value *= x;                     return *this; }
   fix opMulAssign(long x)    { value *= x;                     return *this; }
   fix opMulAssign(double x)  { value = ftofix(fixtof(value) * x); return *this; }

   fix opDivAssign(fix x)    { value = fixdiv(value, x.value);  return *this; }
   fix opDivAssign(int x)    { value /= x;                      return *this; }
   fix opDivAssign(long x)   { value /= x;                      return *this; }
   fix opDivAssign(double x) { value = ftofix(fixtof(value) / x); return *this; }

   fix opShlAssign(int x)    { value <<= x;           return *this; }
   fix opShrAssign(int x)    { value >>= x;           return *this; }

   fix opPostInc() { fix t; t.value = value; value += itofix(1); return t; }
   fix opPostDec() { fix t; t.value = value; value -= itofix(1); return t; }

   fix opNeg() { fix t;  t.value = -value;  return t; }

   fix opAdd(fix x) { fix t = void; t.value = value + x.value; return t; }
   fix opAdd(int x) { fix t = void; t.value = value + itofix(x); return t; }
   fix opAdd(long x) { return opAdd(cast(int)x); }
   fix opAdd(double x) { fix t = void;  t.value = value + ftofix(x);  return t; }

   fix opSub(fix x)    { fix t = void;  t.value = value - x.value;        return t; }
   fix opSub(int x)    { fix t = void;  t.value = value - itofix(x);  return t; }
   fix opSub_r(int x)    { fix t = void;  t.value = itofix(x) - value;  return t; }
   fix opSub(long x)    { return opSub(cast(int)x); }
   fix opSub_r(long x)    { return opSub_r(cast(int)x); }
   fix opSub(double x) { fix t = void;  t.value = value - ftofix(x);  return t; }
   fix opSub_r(double x) { fix t = void;  t.value = ftofix(x) - value;  return t; }

   fix opMul(fix x)    { fix t;  t.value = fixmul(value, x.value);         return t; }
   fix opMul(int x)    { fix t;  t.value = value * x;                  return t; }
   fix opMul(long x)    { fix t;  t.v = cast(int)(v * x);                  return t; }
   fix opMul(double x) { fix t;  t.value = ftofix(fixtof(value) * x);  return t; }

   fix opDiv(fix x) { fix t;  t.v = fixdiv(v, x.v);         return t; }
   fix opDiv(int x)    { fix t;  t.value = v / x;                  return t; }
   fix opDiv_r(int x)    { fix t;  t.v= fixdiv(itofix(x), v);   return t; }
   fix opDiv(long x)   { fix t;  t.v = cast(int)(v / x);                  return t; }
   fix opDiv_r(long x)   { fix t;  t.v = fixdiv(itofix(cast(int)x), v);   return t; }
   fix opDiv(double x) { fix t;  t.v = ftofix(fixtof(v) / x);  return t; }
   fix opDiv_r(double x) { fix t;  t.v = ftofix(x / fixtof(v));  return t; }

   fix opShl(int x)    { fix t;  t.value = value << x;   return t; }
   fix opShr(int x)    { fix t;  t.value = value >> x;   return t; }
   fix opUShr(int x)   { fix t;  t.value = value >>> x;   return t; }

   int opEquals(fix x)       { return (value == x.value);   }
   int opEquals(byte x)      { return (value == itofix(x)); }
   int opEquals(ubyte x)     { return (value == itofix(x)); }
   int opEquals(short x)     { return (value == itofix(x)); }
   int opEquals(ushort x)    { return (value == itofix(x)); }
   int opEquals(int x)       { return (value == itofix(x)); }
   int opEquals(long x)      { return (value == itofix(cast(int)x)); }
   int opEquals(double x)    { return (value == ftofix(x)); }

   int opCmp(fix x) { return value - x.value; }
   int opCmp(int x) { return value - itofix(x); }
   int opCmp(long x) { return value - itofix(cast(int)x); }
   int opCmp(double x) { return value - ftofix(x); }

   fix sqrt()          { fix t;  t.value = fixsqrt(value);    return t; }
   fix cos()           { fix t;  t.value = fixcos(value);     return t; }
   fix sin()           { fix t;  t.value = fixsin(value);     return t; }
   fix tan()           { fix t;  t.value = fixtan(value);     return t; }
   fix acos()          { fix t;  t.value = fixacos(value);    return t; }
   fix asin()          { fix t;  t.value = fixasin(value);    return t; }
   fix atan()          { fix t;  t.value = fixatan(value);    return t; }
   fix atan2(fix x)    { fix t;  t.value = fixatan2(value, x.value);  return t; }

}


/*
 * Free function versions
 */

   fix sqrt(fix x)          { return x.sqrt(); }
   fix cos(fix x)           { return x.cos(); }
   fix sin(fix x)           { return x.sin(); }
   fix tan(fix x)           { return x.tan(); }
   fix acos(fix x)          { return x.acos(); }
   fix asin(fix x)          { return x.asin(); }
   fix atan(fix x)          { return x.atan(); }
   fix atan2(fix x, fix y)  { return x.atan2(y); }


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/