#include <iostream>
#include <cstdlib>
using namespace std;

char buf[10000];
char *ptr = buf;
int freepos[1000];
int freecount = 0;

void* myMalloc( size_t size ) {
	int *sz = NULL;
	void *tmp = NULL;
	char *ctmp;
	int i;
	for (i = freecount - 1; i >= 0; i--) {
		sz = (int*)freepos[i];
		ctmp = (char*)sz;
		ctmp += sizeof(int);
		tmp = ctmp;
		cout << "check free - index:" << i 
			<< " pos:" << (int)tmp - (int)buf
			<< " size:" << *sz << endl;
		if (*sz == size) {
			freepos[i] = freepos[--freecount];
			break;
		}
	}
	if (i < 0) {
		sz = (int*)ptr;
		*sz = size;
		ptr += sizeof(int) + size;
	}
	ctmp = (char*)sz;
	ctmp += sizeof(int);
	tmp = ctmp;
	cout << "call myAlloc - pos:" << (int)tmp - (int)buf
		<< " size:" << *sz
		<< " / recycle:" << i << endl;
	return tmp;
}

void myFree( void* p) {
	char *ctmp = (char*)p;
	ctmp -= sizeof(int);
	int *itmp = (int*)ctmp;
	freepos[freecount++] = (int)itmp;
	cout << "call myFree - pos:" << (int)p - (int)buf
		<< " size:" << *itmp
		<< " / freecount:" << freecount << endl;
}

class Foo
{
	static int c() {
		static int cc = 1;
		return cc++;
	}
	int _id;
public:
	Foo() : _id( c() ) { cout << "new: " << _id << endl; }
	~Foo() { cout << "del: " << _id << endl; }
	int id() const { return _id; }
	static void* operator new( size_t size ) {
		cout << "call new" << endl;
		return myMalloc( size );
	}
	static void operator delete( void* p ) {
		cout << "call delete - id:" << ((Foo*)p)->_id << endl;
		myFree( p );
	}
};

class Bar : public Foo
{
	int n;
public:
	Bar() : n( 0 ) {}
	~Bar() { cout << "BAR!!" << endl; }
};

class Baz : public Bar
{
	int k;
public:
	Baz() : k( 1 ) {}
};

int main() {
	
	Foo foo1, foo2;
	Foo *foo3 = ( Foo* )myMalloc( sizeof( Foo ) ); // コンストラクタが呼ばれない
	Foo *foo4 = ( Foo* )malloc( sizeof( Foo ) ); // コンストラクタが呼ばれない
	Foo *foo5 = ::new Foo;
	Foo *foo6 = new Foo; // Foo::new
	Baz *baz1 = new Baz; // なんと Foo::new が呼ばれる
	Baz baz2;
	
	Baz *baz3 = new Baz;
	Foo *foo7 = new Foo;
	Bar *bar1 = new Bar;
	Foo *foo8 = new Foo;
	delete bar1;
	delete foo7;
	delete baz3;
	baz3 = new Baz;
	foo7 = new Foo;
	
	
	cout << foo1.id() << endl;
	cout << foo2.id() << endl;
	cout << foo3->id() << endl;
	cout << foo4->id() << endl;
	cout << foo5->id() << endl;
	cout << foo6->id() << endl;
	
	myFree( foo3 );
	free( foo4 );
	::delete foo5;
	delete foo6; // Foo::delete
	
	cout << "[baz]" << endl;
	
	delete baz1; // なんと Foo::delete が呼ばれる
	
	cout << "[other]" << endl;
	
	delete bar1;
	delete baz3;
	delete foo7;
	delete foo8;

	cout << "[done]" << endl;

	return 0;
}