ObjFW  Check-in [9b50b86632]

Overview
Comment:Add -[description] for OFObject, OFString, OFArray and OFDictionary.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 9b50b86632e0c041e4e8de0742cdb3fb011a0c1e1396a99021aadbfd601643f6
User & Date: js on 2010-11-13 21:57:09
Other Links: manifest | tags
Context
2010-11-14
23:49
Handle <!DOCTYPE> in OFXMLParser. check-in: 2d28a0fda4 user: js tags: trunk
2010-11-13
21:57
Add -[description] for OFObject, OFString, OFArray and OFDictionary. check-in: 9b50b86632 user: js tags: trunk
21:26
Add -[OFMutableString prependString:]. check-in: 5a75edd60e user: js tags: trunk
Changes

Modified src/OFArray.m from [b812da9162] to [f508012563].

12
13
14
15
16
17
18

19
20
21
22
23
24
25
#include "config.h"

#include <stdarg.h>

#import "OFArray.h"
#import "OFDataArray.h"
#import "OFString.h"

#import "OFExceptions.h"
#import "macros.h"

@implementation OFArray
+ array
{
	return [[[self alloc] init] autorelease];







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "config.h"

#include <stdarg.h>

#import "OFArray.h"
#import "OFDataArray.h"
#import "OFString.h"
#import "OFAutoreleasePool.h"
#import "OFExceptions.h"
#import "macros.h"

@implementation OFArray
+ array
{
	return [[[self alloc] init] autorelease];
270
271
272
273
274
275
276

277
278
279
280
281
282
283
284
285
286
287
288
289
290
291


292
293
294
295
296
297
298
299


300


301
302
303
304
305
306
307
{
	return [self objectsFromIndex: range.start
			      toIndex: range.start + range.length];
}

- (OFString*)componentsJoinedByString: (OFString*)separator
{

	OFString *str;
	OFString **objs = [array cArray];
	size_t i, count = [array count];
	Class cls;
	IMP append;

	if (count == 0)
		return @"";
	if (count == 1)
		return [objs[0] retain];

	str = [OFMutableString string];
	cls = [OFString class];
	append = [str methodForSelector: @selector(appendString:)];



	for (i = 0; i < count - 1; i++) {
		if (![objs[i] isKindOfClass: cls])
			@throw [OFInvalidArgumentException newWithClass: isa
							       selector: _cmd];

		append(str, @selector(appendString:), objs[i]);
		append(str, @selector(appendString:), separator);
	}


	append(str, @selector(appendString:), objs[i]);



	return str;
}

- (BOOL)isEqual: (id)obj
{
	id *objs, *objs2;







>















>
>





|

|
>
>

>
>







271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
{
	return [self objectsFromIndex: range.start
			      toIndex: range.start + range.length];
}

- (OFString*)componentsJoinedByString: (OFString*)separator
{
	OFAutoreleasePool *pool;
	OFString *str;
	OFString **objs = [array cArray];
	size_t i, count = [array count];
	Class cls;
	IMP append;

	if (count == 0)
		return @"";
	if (count == 1)
		return [objs[0] retain];

	str = [OFMutableString string];
	cls = [OFString class];
	append = [str methodForSelector: @selector(appendString:)];

	pool = [[OFAutoreleasePool alloc] init];

	for (i = 0; i < count - 1; i++) {
		if (![objs[i] isKindOfClass: cls])
			@throw [OFInvalidArgumentException newWithClass: isa
							       selector: _cmd];

		append(str, @selector(appendString:), [objs[i] description]);
		append(str, @selector(appendString:), separator);

		[pool releaseObjects];
	}
	append(str, @selector(appendString:), objs[i]);

	[pool release];

	return str;
}

- (BOOL)isEqual: (id)obj
{
	id *objs, *objs2;
343
344
345
346
347
348
349











350
351
352
353
354
355
356
		OF_HASH_ADD(hash, h & 0xFF);
	}

	OF_HASH_FINALIZE(hash);

	return hash;
}












- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t*)state
			   objects: (id*)objects
			     count: (int)count_
{
	size_t count = [array count];








>
>
>
>
>
>
>
>
>
>
>







351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
		OF_HASH_ADD(hash, h & 0xFF);
	}

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString*)description
{
	OFMutableString *ret;

	ret = (OFMutableString*)[self componentsJoinedByString: @", "];
	[ret prependString: @"("];
	[ret appendString: @")"];

	return ret;
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t*)state
			   objects: (id*)objects
			     count: (int)count_
{
	size_t count = [array count];

Modified src/OFDictionary.m from [c675091634] to [cc548c3d18].

12
13
14
15
16
17
18

19
20
21
22
23
24
25
#include "config.h"

#include <string.h>

#import "OFDictionary.h"
#import "OFEnumerator.h"
#import "OFArray.h"

#import "OFAutoreleasePool.h"
#import "OFExceptions.h"
#import "macros.h"

struct of_dictionary_bucket of_dictionary_deleted_bucket = {};

#define BUCKET struct of_dictionary_bucket







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "config.h"

#include <string.h>

#import "OFDictionary.h"
#import "OFEnumerator.h"
#import "OFArray.h"
#import "OFString.h"
#import "OFAutoreleasePool.h"
#import "OFExceptions.h"
#import "macros.h"

struct of_dictionary_bucket of_dictionary_deleted_bucket = {};

#define BUCKET struct of_dictionary_bucket
612
613
614
615
616
617
618




























619
620
621
622
623
624
625
		}
	}

	OF_HASH_FINALIZE(hash);

	return hash;
}




























@end

/// \cond internal
@implementation OFDictionaryEnumerator
-     initWithData: (struct of_dictionary_bucket**)data_
	      size: (uint32_t)size_
  mutationsPointer: (unsigned long*)mutationsPtr_







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
		}
	}

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString*)description
{
	OFMutableString *ret = [OFMutableString stringWithString: @"{"];
	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init], *pool2;
	OFEnumerator *enumerator = [self keyEnumerator];
	id key;
	size_t i;

	i = 0;
	pool2 = [[OFAutoreleasePool alloc] init];

	while ((key = [enumerator nextObject]) != nil) {
		[ret appendString: [key description]];
		[ret appendString: @" = "];
		[ret appendString: [[self objectForKey: key] description]];

		if (++i < count)
			[ret appendString: @"; "];

		[pool2 releaseObjects];
	}
	[ret appendString: @"}"];

	[pool release];

	return ret;
}
@end

/// \cond internal
@implementation OFDictionaryEnumerator
-     initWithData: (struct of_dictionary_bucket**)data_
	      size: (uint32_t)size_
  mutationsPointer: (unsigned long*)mutationsPtr_

Modified src/OFObject.h from [0ecdb91882] to [82b71eb5d5].

36
37
38
39
40
41
42


43
44
45
46
47
48
49
 * \brief A range.
 */
typedef struct __of_range {
	size_t start;
	size_t length;
} of_range_t;



/**
 * \brief The root class for all other classes inside ObjFW.
 */
@interface OFObject
{
	/// The class of the object
	Class isa;







>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
 * \brief A range.
 */
typedef struct __of_range {
	size_t start;
	size_t length;
} of_range_t;

@class OFString;

/**
 * \brief The root class for all other classes inside ObjFW.
 */
@interface OFObject
{
	/// The class of the object
	Class isa;
125
126
127
128
129
130
131







132
133
134
135
136
137
138

/**
 * \param selector The selector for which the type encoding should be returned
 * \return The type encoding of the instance method for the specified selector
 */
+ (const char*)typeEncodingForInstanceSelector: (SEL)selector;








/**
 * Replaces a class method implementation with another implementation.
 *
 * \param newimp The new implementation for the class method
 * \param selector The selector of the class method to replace
 * \return The old implementation
 */







>
>
>
>
>
>
>







127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

/**
 * \param selector The selector for which the type encoding should be returned
 * \return The type encoding of the instance method for the specified selector
 */
+ (const char*)typeEncodingForInstanceSelector: (SEL)selector;

/**
 * Returns a description for the class, which is usually the class name.
 *
 * This is mostly for debugging purposes.
 */
+ (OFString*)description;

/**
 * Replaces a class method implementation with another implementation.
 *
 * \param newimp The new implementation for the class method
 * \param selector The selector of the class method to replace
 * \return The old implementation
 */
239
240
241
242
243
244
245







246
247
248
249
250
251
252
 * Classes containing data (like strings, arrays, lists etc.) should reimplement
 * this!
 *
 * \return A 32 bit hash for the object
 */
- (uint32_t)hash;








/**
 * Adds a pointer to the object's memory pool.
 *
 * This is useful to add memory allocated by functions such as asprintf to the
 * pool so it gets free'd automatically when the object is deallocated.
 *
 * \param ptr A pointer to add to the memory pool







>
>
>
>
>
>
>







248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
 * Classes containing data (like strings, arrays, lists etc.) should reimplement
 * this!
 *
 * \return A 32 bit hash for the object
 */
- (uint32_t)hash;

/**
 * Returns a description for the object.
 *
 * This is mostly for debugging purposes.
 */
- (OFString*)description;

/**
 * Adds a pointer to the object's memory pool.
 *
 * This is useful to add memory allocated by functions such as asprintf to the
 * pool so it gets free'd automatically when the object is deallocated.
 *
 * \param ptr A pointer to add to the memory pool

Modified src/OFObject.m from [0624e5a61b] to [115db6d7a7].

33
34
35
36
37
38
39


40
41
42
43
44
45
46
# import <objc/sarray.h>
#endif

#ifdef _WIN32
# include <windows.h>
#endif



#ifdef OF_ATOMIC_OPS
# import "atomic.h"
#else
# import "threading.h"
#endif

/* A few macros to reduce #ifdefs */







>
>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# import <objc/sarray.h>
#endif

#ifdef _WIN32
# include <windows.h>
#endif

#import "OFString.h"

#ifdef OF_ATOMIC_OPS
# import "atomic.h"
#else
# import "threading.h"
#endif

/* A few macros to reduce #ifdefs */
256
257
258
259
260
261
262





263
264
265
266
267
268
269
	if ((ret = objc_get_type_encoding(self, selector)) == NULL)
		@throw [OFNotImplementedException newWithClass: self
						      selector: selector];

	return ret;
#endif
}






+ (IMP)setImplementation: (IMP)newimp
	  forClassMethod: (SEL)selector
{
#if defined(OF_OBJFW_RUNTIME)
	if (newimp == (IMP)0 || !class_respondsToSelector(self->isa, selector))
		@throw [OFInvalidArgumentException newWithClass: self







>
>
>
>
>







258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
	if ((ret = objc_get_type_encoding(self, selector)) == NULL)
		@throw [OFNotImplementedException newWithClass: self
						      selector: selector];

	return ret;
#endif
}

+ (OFString*)description
{
	return [OFString stringWithCString: [self className]];
}

+ (IMP)setImplementation: (IMP)newimp
	  forClassMethod: (SEL)selector
{
#if defined(OF_OBJFW_RUNTIME)
	if (newimp == (IMP)0 || !class_respondsToSelector(self->isa, selector))
		@throw [OFInvalidArgumentException newWithClass: self
474
475
476
477
478
479
480






481
482
483
484
485
486
487
}

- (uint32_t)hash
{
	/* Classes containing data should reimplement this! */
	return (uint32_t)(uintptr_t)self;
}







- (void)addMemoryToPool: (void*)ptr
{
	void **memchunks;
	size_t memchunks_size;

	memchunks_size = PRE_IVAR->memchunks_size + 1;







>
>
>
>
>
>







481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
}

- (uint32_t)hash
{
	/* Classes containing data should reimplement this! */
	return (uint32_t)(uintptr_t)self;
}

- (OFString*)description
{
	/* Classes containing data should reimplement this! */
	return [OFString stringWithFormat: @"<%s: %p>", [self className], self];
}

- (void)addMemoryToPool: (void*)ptr
{
	void **memchunks;
	size_t memchunks_size;

	memchunks_size = PRE_IVAR->memchunks_size + 1;

Modified src/OFString.m from [04e9fd7c64] to [408783a5f8].

800
801
802
803
804
805
806





807
808
809
810
811
812
813
	OF_HASH_INIT(hash);
	for (i = 0; i < length; i++)
		OF_HASH_ADD(hash, string[i]);
	OF_HASH_FINALIZE(hash);

	return hash;
}






- (of_unichar_t)characterAtIndex: (size_t)index
{
	of_unichar_t c;

	if (![self isUTF8]) {
		if (index >= length)







>
>
>
>
>







800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
	OF_HASH_INIT(hash);
	for (i = 0; i < length; i++)
		OF_HASH_ADD(hash, string[i]);
	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString*)description
{
	return [[self copy] autorelease];
}

- (of_unichar_t)characterAtIndex: (size_t)index
{
	of_unichar_t c;

	if (![self isUTF8]) {
		if (index >= length)

Modified tests/OFArrayTests.m from [c5886d17f7] to [c0fcdd0b1e].

45
46
47
48
49
50
51



52
53
54
55
56
57
58
	TEST(@"+[arrayWithCArray:]", (a[1] = [OFArray arrayWithCArray: c_ary]))

	TEST(@"+[arrayWithCArray:length:]",
	    (a[2] = [OFArray arrayWithCArray: c_ary
				      length: 3]) &&
	    [a[2] isEqual: a[1]])




	TEST(@"-[addObject:]", R([m[0] addObject: c_ary[0]]) &&
	    R([m[0] addObject: c_ary[2]]))

	TEST(@"-[addObject:atIndex:]", R([m[0] addObject: c_ary[1]
						 atIndex: 1]))

	TEST(@"-[count]", [m[0] count] == 3 && [a[0] count] == 3 &&







>
>
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
	TEST(@"+[arrayWithCArray:]", (a[1] = [OFArray arrayWithCArray: c_ary]))

	TEST(@"+[arrayWithCArray:length:]",
	    (a[2] = [OFArray arrayWithCArray: c_ary
				      length: 3]) &&
	    [a[2] isEqual: a[1]])

	TEST(@"-[description]",
	    [[a[0] description ]isEqual: @"(Foo, Bar, Baz)"])

	TEST(@"-[addObject:]", R([m[0] addObject: c_ary[0]]) &&
	    R([m[0] addObject: c_ary[2]]))

	TEST(@"-[addObject:atIndex:]", R([m[0] addObject: c_ary[1]
						 atIndex: 1]))

	TEST(@"-[count]", [m[0] count] == 3 && [a[0] count] == 3 &&

Modified tests/OFDictionaryTests.m from [e289cdd042] to [65e2a63075].

43
44
45
46
47
48
49



50
51
52
53
54
55
56
		 forKey: keys[1]];

	TEST(@"-[objectForKey:]",
	    [[dict objectForKey: keys[0]] isEqual: values[0]] &&
	    [[dict objectForKey: keys[1]] isEqual: values[1]] &&
	    [dict objectForKey: @"key3"] == nil)




	TEST(@"-[keyEnumerator]", (key_enum = [dict keyEnumerator]))
	TEST(@"-[objectEnumerator]", (obj_enum = [dict objectEnumerator]))

	TEST(@"OFEnumerator's -[nextObject]",
	    [[key_enum nextObject] isEqual: keys[0]] &&
	    [[obj_enum nextObject] isEqual: values[0]] &&
	    [[key_enum nextObject] isEqual: keys[1]] &&







>
>
>







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
		 forKey: keys[1]];

	TEST(@"-[objectForKey:]",
	    [[dict objectForKey: keys[0]] isEqual: values[0]] &&
	    [[dict objectForKey: keys[1]] isEqual: values[1]] &&
	    [dict objectForKey: @"key3"] == nil)

	TEST(@"-[description]",
	    [[dict description] isEqual: @"{key1 = value1; key2 = value2}"])

	TEST(@"-[keyEnumerator]", (key_enum = [dict keyEnumerator]))
	TEST(@"-[objectEnumerator]", (obj_enum = [dict objectEnumerator]))

	TEST(@"OFEnumerator's -[nextObject]",
	    [[key_enum nextObject] isEqual: keys[0]] &&
	    [[obj_enum nextObject] isEqual: values[0]] &&
	    [[key_enum nextObject] isEqual: keys[1]] &&

Modified tests/OFObjectTests.m from [961f87c192] to [aec4d67f45].

14
15
16
17
18
19
20






21
22
23
24
25
26
27


28
29
30
31
32
33
34
#import "OFString.h"
#import "OFAutoreleasePool.h"
#import "OFExceptions.h"

#import "TestsAppDelegate.h"

static OFString *module = @"OFObject";







@implementation TestsAppDelegate (OFObjectTests)
- (void)objectTests
{
	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFObject *obj = [[[OFObject alloc] init] autorelease];
	void *p, *q, *r;



	EXPECT_EXCEPTION(@"Detect freeing of memory not allocated by object",
	    OFMemoryNotPartOfObjectException, [obj freeMemory: (void*)1])

	TEST(@"Allocating 4096 bytes",
	    (p = [obj allocMemoryWithSize: 4096]) != NULL)








>
>
>
>
>
>







>
>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#import "OFString.h"
#import "OFAutoreleasePool.h"
#import "OFExceptions.h"

#import "TestsAppDelegate.h"

static OFString *module = @"OFObject";

@interface MyObj: OFObject
@end

@implementation MyObj
@end

@implementation TestsAppDelegate (OFObjectTests)
- (void)objectTests
{
	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFObject *obj = [[[OFObject alloc] init] autorelease];
	void *p, *q, *r;
	OFObject *o;
	MyObj *m;

	EXPECT_EXCEPTION(@"Detect freeing of memory not allocated by object",
	    OFMemoryNotPartOfObjectException, [obj freeMemory: (void*)1])

	TEST(@"Allocating 4096 bytes",
	    (p = [obj allocMemoryWithSize: 4096]) != NULL)

61
62
63
64
65
66
67













68
69
70
			    toSize: 1024]) != NULL)
	[obj freeMemory: p];

	EXPECT_EXCEPTION(@"Detect resizing of memory not allocated by object",
	    OFMemoryNotPartOfObjectException, [obj resizeMemory: (void*)1
							 toSize: 1024])














	[pool drain];
}
@end







>
>
>
>
>
>
>
>
>
>
>
>
>



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
			    toSize: 1024]) != NULL)
	[obj freeMemory: p];

	EXPECT_EXCEPTION(@"Detect resizing of memory not allocated by object",
	    OFMemoryNotPartOfObjectException, [obj resizeMemory: (void*)1
							 toSize: 1024])

	TEST(@"+[description]",
	    [[OFObject description] isEqual: @"OFObject"] &&
	    [[MyObj description] isEqual: @"MyObj"])

	o = [[[OFObject alloc] init] autorelease];
	m = [[[MyObj alloc] init] autorelease];

	TEST(@"-[description]",
	    [[o description] isEqual:
	    ([OFString stringWithFormat: @"<OFObject: %p>", o])] &&
	    [[m description] isEqual:
	    ([OFString stringWithFormat: @"<MyObj: %p>", m])])

	[pool drain];
}
@end

Modified tests/OFStringTests.m from [5c859eec81] to [0feeee8df5].

76
77
78
79
80
81
82


83
84
85
86
87
88
89
	    [@"รŸ" caseInsensitiveCompare: @"โ†’"] == OF_ORDERED_ASCENDING &&
	    [@"AA" caseInsensitiveCompare: @"z"] == OF_ORDERED_ASCENDING &&
	    [[OFString stringWithCString: "ABC"] caseInsensitiveCompare:
	    [OFString stringWithCString: "AbD"]] == [@"abc" compare: @"abd"])

	TEST(@"-[hash] is the same if -[isEqual:] is YES",
	    [s[0] hash] == [s[2] hash])



	TEST(@"-[appendString:] and -[appendCString:]",
	    R([s[1] appendCString: "1๐„ž"]) && R([s[1] appendString: @"3"]) &&
	    R([s[0] appendString: s[1]]) && [s[0] isEqual: @"tรคsโ‚ฌ1๐„ž3"])

	TEST(@"-[length]", [s[0] length] == 7)
	TEST(@"-[cStringLength]", [s[0] cStringLength] == 13)







>
>







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
	    [@"รŸ" caseInsensitiveCompare: @"โ†’"] == OF_ORDERED_ASCENDING &&
	    [@"AA" caseInsensitiveCompare: @"z"] == OF_ORDERED_ASCENDING &&
	    [[OFString stringWithCString: "ABC"] caseInsensitiveCompare:
	    [OFString stringWithCString: "AbD"]] == [@"abc" compare: @"abd"])

	TEST(@"-[hash] is the same if -[isEqual:] is YES",
	    [s[0] hash] == [s[2] hash])

	TEST(@"-[description]", [[s[0] description] isEqual: s[0]])

	TEST(@"-[appendString:] and -[appendCString:]",
	    R([s[1] appendCString: "1๐„ž"]) && R([s[1] appendString: @"3"]) &&
	    R([s[0] appendString: s[1]]) && [s[0] isEqual: @"tรคsโ‚ฌ1๐„ž3"])

	TEST(@"-[length]", [s[0] length] == 7)
	TEST(@"-[cStringLength]", [s[0] cStringLength] == 13)