# include <memory>
# include <tr1/memory>
# include <stdio.h>
# include <stdlib.h>

using namespace std;
using namespace tr1;

int const RESOLUTION = 5000;

void set_fpu (unsigned int mode) {
  asm ("fldcw %0" : : "m" (*&mode));
}

namespace Test1 {
    int iters(int max_iter,double xc,double yc) {
       double x = xc;
       double y = yc;
       for(int count = 0;count<max_iter;count++) {
          if( x*x + y*y >= 4.0) { return count; }
          double tmp = x*x-y*y+xc;
          y = 2.0 * x * y + yc;
          x = tmp;
       }
       return max_iter;
    }
}

//-----------------------------------------------------------------

namespace Test2 {
    class Complex {
    public:
       Complex(double xc,double yc) : x(xc), y(yc) { }

       double norm_square() {
          return x*x+y*y;
       }

       double x;
       double y;

       auto_ptr<Complex> operator*(const Complex * other) {
         return auto_ptr<Complex>(new Complex(x*other->x-y*other->y,
                         x*other->y+y*other->x));
       }

       auto_ptr<Complex> operator+(const Complex * other) {
         return auto_ptr<Complex>(new Complex(x + other->x, y + other->y));
       }

    };

    int iters(int max_iter,double xc,double yc) {
      std::auto_ptr<Complex> c (new Complex(xc,yc));
      std::auto_ptr<Complex> z (new Complex(xc,yc));
       for(int count = 0;count<max_iter;count++) {
          if( z -> norm_square() >= 4.0 ) { return count; }
          z = *(*z * z.get ()) + c.get ();
       }

       return max_iter;
    }
}
//-----------------------------------------------------------------

namespace Test3 {
    class Complex {
    public:
       Complex(double xc,double yc) : x(xc), y(yc) { }

       double norm_square() {
          return x*x+y*y;
       }

       double x;
       double y;

       shared_ptr<Complex> operator*(const Complex * other) {
         return shared_ptr<Complex>(new Complex(x*other->x-y*other->y,
                         x*other->y+y*other->x));
       }

       shared_ptr<Complex> operator+(const Complex * other) {
         return shared_ptr<Complex>(new Complex(x + other->x, y + other->y));
       };

    };

    int iters(int max_iter,double xc,double yc) {
      shared_ptr<Complex> c (new Complex(xc,yc));
      shared_ptr<Complex> z (new Complex(xc,yc));
       for(int count = 0;count<max_iter;count++) {
          if( z -> norm_square() >= 4.0 ) { return count; }
          z = *(*z * z.get ()) + c.get ();
       }

       return max_iter;
    }
}

//-----------------------------------------------------------------

namespace Test4 {
    class Complex {
    public:
       Complex(double xc,double yc) : x(xc), y(yc) { }

       double norm_square() { return x*x+y*y; }

       double x;
       double y;

       shared_ptr<Complex> operator*(const shared_ptr<Complex> other) {
         return shared_ptr<Complex>(new Complex(x*other->x-y*other->y,
                         x*other->y+y*other->x));
       }

       shared_ptr<Complex> operator+(const shared_ptr<Complex> other) {
         return shared_ptr<Complex>(new Complex(x + other->x, y + other->y));
       };

    };

    int iters(int max_iter,double xc,double yc) {
      shared_ptr<Complex> c (new Complex(xc,yc));
      shared_ptr<Complex> z (new Complex(xc,yc));
       for(int count = 0;count<max_iter;count++) {
          if( z -> norm_square() >= 4.0 )  return count;
          z = *(*z * z) + c;
       }

       return max_iter;
    }
}

namespace Test45 {
    class Complex {
    public:
       Complex(double xc,double yc) : x(xc), y(yc) { }

       double norm_square() { return x*x+y*y; }

       double x;
       double y;

       Complex* operator*(const Complex* other) {
         return new Complex(x*other->x-y*other->y, x*other->y+y*other->x);
       }

       Complex* operator+(const Complex* other) {
         return new Complex(x + other->x, y + other->y);
       };

    };

    int iters(int max_iter,double xc,double yc) {
      Complex* c = new Complex(xc,yc);
      Complex* z = new Complex(xc,yc);
       for(int count = 0;count<max_iter;count++) {
	  if( z -> norm_square() >= 4.0 ) {
	    delete z;
	    delete c;
	    return count;
	  }
	  Complex* prev_z = z;
	  Complex* mul;
          z = *(mul = (*z * z)) + c;
	  delete prev_z;
	  delete mul;
       }

       delete z;
       delete c;
       return max_iter;
    }
}

#include <gc/gc.h>

void* operator new(size_t size)
{
    return GC_MALLOC_UNCOLLECTABLE(size);
}

struct collectable_tag {
} collectable;

void* operator new(size_t size, collectable_tag)
{
    return GC_MALLOC(size);
}

void operator delete(void* ptr)
{
    return GC_FREE(ptr);
}

namespace Test5 {
    class Complex {
    public:
       Complex(double xc,double yc) : x(xc), y(yc) { }

       double norm_square() { return x*x+y*y; }

       double x;
       double y;

       Complex* operator*(const Complex* other) {
         return new (collectable) Complex(x*other->x-y*other->y, x*other->y+y*other->x);
       }

       Complex* operator+(const Complex* other) {
         return new (collectable) Complex(x + other->x, y + other->y);
       };

    };

    int iters(int max_iter,double xc,double yc) {
      Complex* c = new(collectable) Complex(xc,yc);
      Complex* z = new(collectable) Complex(xc,yc);
       for(int count = 0;count<max_iter;count++) {
          if( z -> norm_square() >= 4.0 )  return count;
          z = *(*z * z) + c;
       }

       // printf("heap=%ld, counts=%d\n", GC_get_heap_size(), GC_gc_no);
       return max_iter;
    }
}

namespace Test6 {
    class Complex {
    public:
       Complex(double xc,double yc) : x(xc), y(yc) { }

       double norm_square() { return x*x+y*y; }

       double x;
       double y;

       Complex* operator*(const Complex* other) {
         return new Complex(x*other->x-y*other->y, x*other->y+y*other->x);
       }

       Complex* operator+(const Complex* other) {
         return new Complex(x + other->x, y + other->y);
       };

    };

    int iters(int max_iter,double xc,double yc) {
      Complex* c = new Complex(xc,yc);
      Complex* z = new Complex(xc,yc);
       for(int count = 0;count<max_iter;count++) {
          if( z -> norm_square() >= 4.0 ) {
	    delete z;
	    delete c;
	    return count;
	  }
	  Complex* prev_z = z;
	  Complex* mul;
          z = *(mul = (*z * z)) + c;
	  delete prev_z;
	  delete mul;
       }

       delete z;
       delete c;
       return max_iter;
    }
}

//-----------------------------------------------------------------

int run(int iters(int max_iter,double xc,double yc)) {
   clock_t const st = clock();
   int    max_val = RESOLUTION/2;
   int    min_val = -max_val;
   double mul = 2.0 / max_val;
   int    count = 0;
   for(int i=min_val;i<=max_val;i++)
   for(int j=min_val;j<=max_val;j++)
     count += iters(100,mul*i,mul*j);
   printf("result: %d\n",count);
   clock_t const en = clock();
   printf ("Time=%g\n", double (en - st) / CLOCKS_PER_SEC);
   fflush (stdout);
}

int main ()
{
  set_fpu (0x27F);
  run (Test1::iters);
  run (Test2::iters);
  run (Test3::iters);
  run (Test4::iters);
  run (Test45::iters);
  run (Test5::iters);
  run (Test6::iters);
  return 0;
}

/*
g++ v=4.3.3
proc: AMD Athlon(tm) Dual Core Processor 4850e, 2500MHz
cmd: g++ -lgc -O6 -o main main.cpp
result: 290068052
Time=2.25
result: 290068052
Time=57.37
result: 290068052
Time=131.66
result: 290068052
Time=142.14
result: 290068052
Time=55.03
result: 290068052
Time=36.06 <------- this is with collector
result: 290068052
Time=54.13
*/

