//
//	MiscObjectRecycler.h -- a category to speed up alloc/free of piddly objects
//		Written by Don Yacktman (c) 1994 by Don Yacktman.
//				Version 1.0.  All rights reserved.
//
//		This notice may not be removed from this source code.
//
//	This object is included in the MiscKit by permission from the author
//	and its use is governed by the MiscKit license, found in the file
//	"LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
//	for a list of all applicable permissions and restrictions.
//	

#import "MiscObjectRecycler.h"
#import <objc/objc-runtime.h>

//#define MISC_SLOW_BUT_SAFE // define if you are paranoid

static id _recyclerHash = nil;  // holds all the List objects (recyclers),
		// one for each class.  They are created on demand, so a class
		// that doesn't recycle won't take up extra space.

@interface Object(MiscObjectRecyclerPrivate)

+ recyclers; // returns the HashTable full of recyclers

@end

@implementation Object(MiscObjectRecycler)

+ recyclers
{
	if (!_recyclerHash) {
		_recyclerHash = [[HashTable alloc]
				initKeyDesc:"@" valueDesc:"@" capacity:0];
	}
	return _recyclerHash;
}

+ recycler
{
	return [self recyclerForClass:self];
}

+ recyclerForClass:aClass
{
	id theRecycler = [[self recyclers] valueForKey:aClass];
	if (!theRecycler) {
		theRecycler = [[List alloc] initCount:0];
		[[self recyclers] insertKey:aClass value:theRecycler];
	}
	return theRecycler;
}

+ recyclerForClassName:(const char *)className;
{
	return [self recyclerForClass:objc_lookUpClass(className)];
}

+ newFromRecycler
{	// We remove the last object because it is faster.  If we took
	// the first object, the list would shift all the objects down
	// to fill the hole.  This way there's no shifting.  O(1) instead
	// of O(n) could make a big difference here!
	id ret = nil;
	id theObject = [[self recycler] removeLastObject];
	if (!theObject) {
		theObject = [self alloc];
		ret = [self firstInitObject:theObject];
	} else {
		ret = [self reInitObject:theObject];
	}
	return ret;
}

+ reInitObject:anObject
// override this if you need to re-init your object in a special way
{
	return [anObject init];
}

+ firstInitObject:anObject
// override this if you need to init your object in a special way
// the first time around
{
	return [anObject init];
}

- recycle
{	// just like free, we go out or circulation, but we don't free.
	// we just wait around until they need us again.
	// We add it as the last object because it is faster.  If we inserted
	// it as the first object, the list would shift all the objects up
	// to make room.  This way there's no shifting.  O(1) instead
	// of O(n) could make a big difference here!
#ifdef MISC_SLOW_BUT_SAFE
	[[[self class] recycler] addObjectIfAbsent:self];
#else
	[[[self class] recycler] addObject:self];
#endif
	return nil;
}

@end
