ObjFW  Artifact [e6c815e41d]

Artifact e6c815e41db5681906011425d30a58369128d6d4769b08a5b1b9a6aae8e9daa6:

  • File src/OFConstantString.m — part of check-in [28170f5f65] at 2012-03-15 11:29:24 on branch trunk — Greatly improve OFObject's memory handling and performance.

    A linked-list is put before each memory chunk allocated instead of
    having an array of all memory chunks. This means only one malloc now
    instead of one malloc and one realloc. This also means that when
    checking reallocs and frees, it's no longer necessary to iterate through
    all memory chunks, as the linked list also contains the owner, meaning
    realloc and free are no longer O(n), but O(1) now.

    As allocating bigger chunks seems to be a little bit slower than smaller
    chunks, it seems that this is slightly slower in benchmarks if only very small
    chunks are allocated. However, measuring real world usage, it's a lot faster. (user: js, size: 9959) [annotate] [blame] [check-ins using] [more...]


/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   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.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.
 */

#include "config.h"

#define OF_CONSTANT_STRING_M

#include <stdlib.h>
#include <string.h>

#import "OFConstantString.h"
#import "OFString_UTF8.h"

#import "OFInitializationFailedException.h"
#import "OFInvalidEncodingException.h"
#import "OFNotImplementedException.h"
#import "OFOutOfMemoryException.h"

#if defined(OF_APPLE_RUNTIME) && !defined(__OBJC2__)
# import <objc/runtime.h>

struct {
	struct class *isa, *super_class;
	const char *name;
	long version, info, instance_size;
	struct ivar_list *ivars;
	struct method_list **methodLists;
	struct cache *cache;
	struct protocol_list *protocols;
	const char *ivar_layout;
	struct class_ext *ext;
} _OFConstantStringClassReference;
#endif

@interface OFString_const: OFString_UTF8
@end

@implementation OFString_const
+ alloc
{
	@throw [OFNotImplementedException exceptionWithClass: self
						    selector: _cmd];
}


- (void*)allocMemoryWithSize: (size_t)size
{
	@throw [OFNotImplementedException exceptionWithClass: isa
						    selector: _cmd];
}

- (void*)allocMemoryForNItems: (size_t)nitems
		     withSize: (size_t)size
{
	@throw [OFNotImplementedException exceptionWithClass: isa
						    selector: _cmd];
}

- (void*)resizeMemory: (void*)ptr
	       toSize: (size_t)size
{
	@throw [OFNotImplementedException exceptionWithClass: isa
						    selector: _cmd];
}

- (void*)resizeMemory: (void*)ptr
	     toNItems: (size_t)nitems
	     withSize: (size_t)size
{
	@throw [OFNotImplementedException exceptionWithClass: isa
						    selector: _cmd];
}

- (void)freeMemory: (void*)ptr
{
	@throw [OFNotImplementedException exceptionWithClass: isa
						    selector: _cmd];
}

- retain
{
	return self;
}

- autorelease
{
	return self;
}

- (unsigned int)retainCount
{
	return OF_RETAIN_COUNT_MAX;
}

- (void)release
{
}

- (void)dealloc
{
	@throw [OFNotImplementedException exceptionWithClass: isa
						    selector: _cmd];
	[super dealloc];	/* Get rid of a stupid warning */
}
@end

@implementation OFConstantString
+ (void)load
{
#if defined(OF_APPLE_RUNTIME) && !defined(__OBJC2__)
	/*
	 * objc_setFutureClass suddenly stopped working as OFConstantString
	 * became more complex. So the only solution is to make
	 * _OFConstantStringClassRerence the actual class, but there is no
	 * objc_initializeClassPair in 10.5.  However, objc_allocateClassPair
	 * does not register the new class with the subclass in the ObjC1
	 * runtime like the ObjC2 runtime does, so this workaround should be
	 * fine.
	 */
	Class class;

	if ((class = objc_allocateClassPair(self, "OFConstantString_hack",
	    0)) == NULL)
		@throw [OFInitializationFailedException
		    exceptionWithClass: self];
	memcpy(&_OFConstantStringClassReference, class,
	    sizeof(_OFConstantStringClassReference));
	free(class);
	objc_registerClassPair((Class)&_OFConstantStringClassReference);
#endif
}

- (void)finishInitialization
{
	struct of_string_utf8_ivars *ivars;

	if ((ivars = malloc(sizeof(*ivars))) == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithClass: isa
			 requestedSize: sizeof(*ivars)];
	memset(ivars, 0, sizeof(*ivars));

	ivars->cString = cString;
	ivars->cStringLength = cStringLength;

	switch (of_string_check_utf8(ivars->cString, ivars->cStringLength,
	    &ivars->length)) {
	case 1:
		ivars->UTF8 = YES;
		break;
	case -1:
		free(ivars);
		@throw [OFInvalidEncodingException exceptionWithClass: isa];
	}

	cString = (char*)ivars;
	isa = [OFString_const class];
}

+ alloc
{
	@throw [OFNotImplementedException exceptionWithClass: self
						    selector: _cmd];
}

- (void*)allocMemoryWithSize: (size_t)size
{
	@throw [OFNotImplementedException exceptionWithClass: isa
						    selector: _cmd];
}

- (void*)allocMemoryForNItems: (size_t)nitems
		     withSize: (size_t)size
{
	@throw [OFNotImplementedException exceptionWithClass: isa
						    selector: _cmd];
}

- (void*)resizeMemory: (void*)ptr
	       toSize: (size_t)size
{
	@throw [OFNotImplementedException exceptionWithClass: isa
						    selector: _cmd];
}

- (void*)resizeMemory: (void*)ptr
	     toNItems: (size_t)nitems
	     withSize: (size_t)size
{
	@throw [OFNotImplementedException exceptionWithClass: isa
						    selector: _cmd];
}

- (void)freeMemory: (void*)ptr
{
	@throw [OFNotImplementedException exceptionWithClass: isa
						    selector: _cmd];
}

- retain
{
	return self;
}

- autorelease
{
	return self;
}

- (unsigned int)retainCount
{
	return OF_RETAIN_COUNT_MAX;
}

- (void)release
{
}

- (void)dealloc
{
	@throw [OFNotImplementedException exceptionWithClass: isa
						    selector: _cmd];
	[super dealloc];	/* Get rid of a stupid warning */
}

/*
 * In all following methods, the constant string is converted to an
 * OFString_UTF8 and the message sent again.
 */

/* From protocol OFCopying */
- copy
{
	[self finishInitialization];

	return [self copy];
}

/* From protocol OFMutableCopying */
- mutableCopy
{
	[self finishInitialization];

	return [self mutableCopy];
}

/* From protocol OFComparing */
- (of_comparison_result_t)compare: (id)object
{
	[self finishInitialization];

	return [self compare: object];
}

/* From OFObject, but reimplemented in OFString */
- (BOOL)isEqual: (id)object
{
	[self finishInitialization];

	return [self isEqual: object];
}

- (uint32_t)hash
{
	[self finishInitialization];

	return [self hash];
}

- (OFString*)description
{
	[self finishInitialization];

	return [self description];
}

/* From OFString */
- (const char*)UTF8String
{
	[self finishInitialization];

	return [self UTF8String];
}

- (const char*)cStringWithEncoding: (of_string_encoding_t)encoding
{
	[self finishInitialization];

	return [self cStringWithEncoding: encoding];
}

- (size_t)length
{
	[self finishInitialization];

	return [self length];
}

- (size_t)UTF8StringLength
{
	[self finishInitialization];

	return [self UTF8StringLength];
}

- (size_t)cStringLengthWithEncoding: (of_string_encoding_t)encoding
{
	[self finishInitialization];

	return [self cStringLengthWithEncoding: encoding];
}

- (of_comparison_result_t)caseInsensitiveCompare: (OFString*)otherString
{
	[self finishInitialization];

	return [self caseInsensitiveCompare: otherString];
}

- (of_unichar_t)characterAtIndex: (size_t)index
{
	[self finishInitialization];

	return [self characterAtIndex: index];
}

- (void)getCharacters: (of_unichar_t*)buffer
	      inRange: (of_range_t)range
{
	[self finishInitialization];

	return [self getCharacters: buffer
			   inRange: range];
}

- (size_t)indexOfFirstOccurrenceOfString: (OFString*)string
{
	[self finishInitialization];

	return [self indexOfFirstOccurrenceOfString: string];
}

- (size_t)indexOfLastOccurrenceOfString: (OFString*)string
{
	[self finishInitialization];

	return [self indexOfLastOccurrenceOfString: string];
}

- (BOOL)containsString: (OFString*)string
{
	[self finishInitialization];

	return [self containsString: string];
}

- (OFString*)substringWithRange: (of_range_t)range
{
	[self finishInitialization];

	return [self substringWithRange: range];
}

- (OFString*)stringByAppendingString: (OFString*)string
{
	[self finishInitialization];

	return [self stringByAppendingString: string];
}

- (OFString*)stringByPrependingString: (OFString*)string
{
	[self finishInitialization];

	return [self stringByPrependingString: string];
}

- (OFString*)uppercaseString
{
	[self finishInitialization];

	return [self uppercaseString];
}

- (OFString*)lowercaseString
{
	[self finishInitialization];

	return [self lowercaseString];
}

- (OFString*)stringByDeletingLeadingWhitespaces
{
	[self finishInitialization];

	return [self stringByDeletingLeadingWhitespaces];
}

- (OFString*)stringByDeletingTrailingWhitespaces
{
	[self finishInitialization];

	return [self stringByDeletingTrailingWhitespaces];
}

- (OFString*)stringByDeletingEnclosingWhitespaces
{
	[self finishInitialization];

	return [self stringByDeletingEnclosingWhitespaces];
}

- (BOOL)hasPrefix: (OFString*)prefix
{
	[self finishInitialization];

	return [self hasPrefix: prefix];
}

- (BOOL)hasSuffix: (OFString*)suffix
{
	[self finishInitialization];

	return [self hasSuffix: suffix];
}

- (OFArray*)componentsSeparatedByString: (OFString*)delimiter
{
	[self finishInitialization];

	return [self componentsSeparatedByString: delimiter];
}

- (OFArray*)pathComponents
{
	[self finishInitialization];

	return [self pathComponents];
}

- (OFString*)lastPathComponent
{
	[self finishInitialization];

	return [self lastPathComponent];
}

- (OFString*)stringByDeletingLastPathComponent
{
	[self finishInitialization];

	return [self stringByDeletingLastPathComponent];
}

- (intmax_t)decimalValue
{
	[self finishInitialization];

	return [self decimalValue];
}

- (uintmax_t)hexadecimalValue
{
	[self finishInitialization];

	return [self hexadecimalValue];
}

- (float)floatValue
{
	[self finishInitialization];

	return [self floatValue];
}

- (double)doubleValue
{
	[self finishInitialization];

	return [self doubleValue];
}

- (const of_unichar_t*)unicodeString
{
	[self finishInitialization];

	return [self unicodeString];
}

- (const uint16_t*)UTF16String
{
	[self finishInitialization];

	return [self UTF16String];
}

- (void)writeToFile: (OFString*)path
{
	[self finishInitialization];

	return [self writeToFile: path];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block
{
	[self finishInitialization];

	return [self enumerateLinesUsingBlock: block];
}
#endif
@end