/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
 *   Jonathan Schleifer <js@heap.zone>
 *
 * 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.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

/*
 * This file replaces NSAutoreleasePool with OFAutoreleasePool when it is
 * linked.
 * This is done so there is no conflict because OFBlocks are used (blocks are
 * OFBlocks as soon as ObjFW is linked). An application expecting an NSBlock,
 * but getting an OFBlock because ObjFW is linked, would fail to autorelease
 * the block otherwise, as the block would be in an OFAutoreleasePool. By
 * replacing NSAutoreleasePool with OFAutoreleasePool, the application will
 * still properly free the autoreleased block.
 * With autorelease pools now being part of the runtime, this is not really
 * necessary anymore, as both, ObjFW and Foundation, use the runtime's pools if
 * available. However, this is kept for compatibility with older versions of
 * OS X, which don't ship with a runtime with autorelease pools.
 */

#include "config.h"

#import <objc/runtime.h>

#import "OFAutoreleasePool.h"

static id
alloc(Class self, SEL _cmd)
{
	return [OFAutoreleasePool alloc];
}

static void
addObject(Class self, SEL _cmd, id obj)
{
	[OFAutoreleasePool addObject: obj];
}

static id
autorelease(id self, SEL _cmd)
{
	[OFAutoreleasePool addObject: self];

	return self;
}

OF_CONSTRUCTOR()
{
	Class NSAutoreleasePool = objc_getClass("NSAutoreleasePool");
	Class NSObject = objc_getClass("NSObject");
	Method allocMethod;
	Method addObjectMethod;
	Method autoreleaseMethod;

	if (NSAutoreleasePool == Nil || NSObject == Nil)
		return;

	allocMethod = class_getClassMethod(NSAutoreleasePool,
	    @selector(alloc));
	addObjectMethod = class_getClassMethod(NSAutoreleasePool,
	    @selector(addObject:));
	autoreleaseMethod = class_getInstanceMethod(NSObject,
	    @selector(autorelease));

	if (allocMethod == NULL || addObjectMethod == NULL ||
	    autoreleaseMethod == NULL)
		return;

	class_replaceMethod(object_getClass(NSAutoreleasePool),
	    @selector(alloc), (IMP)alloc, method_getTypeEncoding(allocMethod));
	class_replaceMethod(object_getClass(NSAutoreleasePool),
	    @selector(addObject:), (IMP)addObject,
	    method_getTypeEncoding(addObjectMethod));
	class_replaceMethod(NSObject, @selector(autorelease),
	    (IMP)autorelease, method_getTypeEncoding(autoreleaseMethod));
}
