ObjFW  Artifact [14bd700788]

Artifact 14bd700788db60d590600e6546ba7ca4a3927665f1207cf608065b20ecaae3cf:

  • File src/OFAutoreleasePool.m — part of check-in [f92e1c77a0] at 2010-07-08 09:20:54 on branch trunk — Optimize OFAutoreleasePool.

    It always allocates memory for 16 objects now. releaseObjects does not
    free the memory allocated to store objects so that the same number of
    objects can be stored in the autorelease pool again without the need to
    allocate memory. This will give loops creating lots of objects a huge
    performance boost. (user: js, size: 3837) [annotate] [blame] [check-ins using]


/*
 * Copyright (c) 2008 - 2010
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE included in
 * the packaging of this file.
 */

#include "config.h"

#include <stdlib.h>

#import "OFAutoreleasePool.h"
#import "OFArray.h"
#import "OFExceptions.h"

#ifdef OF_THREADS
# import "threading.h"

#define GROW_SIZE 16

static of_tlskey_t first_key, last_key;
#else
static OFAutoreleasePool *first = nil, *last = nil;
#endif

@implementation OFAutoreleasePool
#ifdef OF_THREADS
+ (void)initialize
{
	if (self != [OFAutoreleasePool class])
		return;

	if (!of_tlskey_new(&first_key) || !of_tlskey_new(&last_key))
		@throw [OFInitializationFailedException newWithClass: self];
}
#endif

+ (void)addObjectToTopmostPool: (OFObject*)obj
{
#ifdef OF_THREADS
	id last = of_tlskey_get(last_key);
#endif

	if (last == nil) {
		@try {
			[[self alloc] init];
		} @catch (OFException *e) {
			[obj release];
			@throw e;
		}

#ifdef OF_THREADS
		last = of_tlskey_get(last_key);
#endif
	}

	if (last == nil) {
		[obj release];
		@throw [OFInitializationFailedException newWithClass: self];
	}

	@try {
		[last addObject: obj];
	} @catch (OFException *e) {
		[obj release];
		@throw e;
	}
}

+ (void)releaseAll
{
#ifdef OF_THREADS
	[of_tlskey_get(first_key) release];
#else
	[first release];
#endif
}

- init
{
#ifdef OF_THREADS
	id first;
#endif

	self = [super init];

#ifdef OF_THREADS
	first = of_tlskey_get(first_key);
	prev = of_tlskey_get(last_key);

	if (!of_tlskey_set(last_key, self)) {
		Class c = isa;
		[super dealloc];
		@throw [OFInitializationFailedException newWithClass: c];
	}
#else
	prev = last;
	last = self;
#endif

	if (first == nil) {
#ifdef OF_THREADS
		if (!of_tlskey_set(first_key, self)) {
			Class c = isa;

			of_tlskey_set(last_key, prev);

			[super dealloc];
			@throw [OFInitializationFailedException
			    newWithClass: c];
		}
#else
		first = self;
#endif
	}

	if (prev != nil)
		prev->next = self;

	size = GROW_SIZE;
	@try {
		objects = [self allocMemoryForNItems: GROW_SIZE
					    withSize: sizeof(id)];
	} @catch (OFException *e) {
		[self dealloc];
		@throw e;
	}

	return self;
}

- (void)addObject: (OFObject*)obj
{
	if (count + 1 > size) {
		objects = [self resizeMemory: objects
				    toNItems: size + GROW_SIZE
				    withSize: sizeof(id)];
		size += GROW_SIZE;
	}

	objects[count] = obj;
	count++;
}

- (void)releaseObjects
{
	size_t i;

	[next releaseObjects];

	for (i = 0; i < count; i++)
		[objects[i] release];

	count = 0;
}

- (void)release
{
	[self dealloc];
}

- (void)drain
{
	[self dealloc];
}

- (void)dealloc
{
	size_t i;

	[next dealloc];

	for (i = 0; i < count; i++)
		[objects[i] release];

	/*
	 * If of_tlskey_set fails, this is a real problem. The best we can do
	 * is to not change the pool below the current pool and stop
	 * deallocation. This way, new objects will be added to the current
	 * pool, but released when the pool below gets released - and maybe
	 * the pool itself will be released as well then, because maybe
	 * of_tlskey_set will work this time.
	 */
#ifdef OF_THREADS
	if (!of_tlskey_set(last_key, prev))
		return;
#else
	last = prev;
#endif

	if (prev != nil)
		prev->next = nil;

	/*
	 * If of_tlskey_set fails here, this is even worse, as this will
	 * definitely be a memory leak. But this should never happen anyway.
	 */
#ifdef OF_THREADS
	if (of_tlskey_get(first_key) == self)
		if (!of_tlskey_set(first_key, nil))
			return;
#else
	if (first == self)
		first = nil;
#endif

	[super dealloc];
}

- retain
{
	@throw [OFNotImplementedException newWithClass: isa
					      selector: _cmd];
}

- autorelease
{
	@throw [OFNotImplementedException newWithClass: isa
					      selector: _cmd];
}
@end