// ### OpenSanAndreas ###
// memory management (pools and block allocators)

// TODO: возможно, проще будет переделать все на bloak allocator-ы
//	требуется проверить, как это будет пос скорости по сравнению с пулами

#pragma pack(push,1)
// TODO: make template class ?
template<typename T> class CPoolBase {
public:
	CPoolBase (int capacity, int blockSize) {
		// TODO: нормально выровнять 
		// TODO: сделать автоматическое определение blockSize (if (!blockSize) blockSize = sizeof (T);)
		capacity = (capacity+3)&~3;	// align object data
	
		flags = new BYTE[(blockSize+1)*capacity];	//	выделяем один блок и для флагов, и для объектов 
		objects = flags+capacity;

		size = capacity;
		top = -1;
		initialized = 1;
		_f11 = 0;
		objectSize = blockSize;

		memset (flags, 0x80, capacity);	// mark all objects as free
	}

	~CPoolBase () {
		if (flags)
			delete flags;
	}

	T*	allocate () {
		bool loop = false;

		do {
			top++;
			if (top >= size) {
				top = 0;
				if (loop)
					return NULL;
				loop = true;
			}
		} while (!(flags[top] & 0x80));

		flags[top] = (flags[top]+1)&0x7F;
		return (T *)(objects+top*objectSize);
	}

	void	release (T* ptr) {
		int i = (((BYTE *)ptr)-objects)/objectSize;
		// assert (i < size);
		flags[i] |= 0x80;
		if (i < top)
			top = i;
	}

	short	indexOf (T* ptr) {
		BYTE * p = (BYTE *)ptr;
		int i = (p-objects)/objectSize;
		if (i < 0 || i >= size)
			return -1;
	// DEBUG:
		if ((p-objects)%objectSize) 
			debug ("ERROR: pool indexOf from non-object pointer\n");
		return (short)i;
	}

	T*	at (int index) {
		if (index >= size || index < 0 || flags[index]&0x80)
			return NULL;
		return (T *)(objects+index*objectSize);
	}

	BYTE *	objects;
	BYTE *	flags;
	int		size;
	int		top;
	BYTE	initialized;
	BYTE	_f11;
	WORD	objectSize;	
};

class CPool : public CPoolBase<BYTE> {
public:
	CPool (int capacity, int blockSize) : CPoolBase (capacity, blockSize) {}
};
#pragma pack(pop)


extern void allocatePools ();	// TODO: move into memory manager constructor
extern void shutdownPools ();	// TODO: move into memory manager destructor

extern void initTxdPool (); // >> 731F20 (XREF: createWorld)

extern CPool ** ptrNodeSinglePool;
extern CPool ** ptrNodeDoublePool;
extern CPool ** entryInfoNodePool;
extern CPool ** pedPool;
extern CPool ** vehiclePool;
extern CPool ** buildingPool;
extern CPool ** objectPool;
extern CPool ** dummyPool;
extern CPool ** colModelPool;
extern CPool ** taskPool;
extern CPool ** eventPool;
extern CPool ** pointRoutePool;
extern CPool ** patrolRoutePool;
extern CPool ** nodeRoutePool;
extern CPool ** taskAllocatorPool;
extern CPool ** pedIntelligencePool;
extern CPool ** pedAttractorPool;

extern CPool ** envMapPipeMatDataPool;
extern CPool ** envMapPipeAtmDataPool;
extern CPool ** specMapPipeMatDataPool;

// extern CPool ** txdPool;		// see comment in ogTextures.h

extern CPool ** stuntJumpPool;

extern CPool ** vehicleStructPool;
