ObjFW  Check-in [f975b722df]

Overview
Comment:Add -[OFArray componentsJoinedByString:options:].

This allows to skip empty components.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: f975b722df26ebf61780382a51dcb44684e31631f667dcbd022541f7b9efd1ae
User & Date: js on 2013-08-25 12:14:46
Other Links: manifest | tags
Context
2013-08-25
20:42
Fix backtraces when using the Apple runtime. check-in: 0e854d19bf user: js tags: trunk
12:14
Add -[OFArray componentsJoinedByString:options:]. check-in: f975b722df user: js tags: trunk
2013-08-22
12:38
Fix ObjFW.h. check-in: cbe0df82d9 user: js tags: trunk
Changes

Modified src/OFArray.h from [2c8fc0a38f] to [22e902db82].

31
32
33
34
35
36
37

38
39
40
41
42
43
44
45
#import "OFMessagePackRepresentation.h"

/*! @file */

@class OFString;

enum {

	OF_SORT_OPTIONS_DESCENDING = 1
};

#ifdef OF_HAVE_BLOCKS
/*!
 * @brief A block for enumerating an OFArray.
 *
 * @param object The current object







>
|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#import "OFMessagePackRepresentation.h"

/*! @file */

@class OFString;

enum {
	OF_ARRAY_SKIP_EMPTY = 1,
	OF_ARRAY_SORT_DESCENDING = 2,
};

#ifdef OF_HAVE_BLOCKS
/*!
 * @brief A block for enumerating an OFArray.
 *
 * @param object The current object
264
265
266
267
268
269
270














271
272
273
274
275
276
277
278
279
280
281

















282
283
284
285
286
287
288
 * @brief Creates a string by joining all objects of the array.
 *
 * @param separator The string with which the objects should be joined
 * @return A string containing all objects joined by the separator
 */
- (OFString*)componentsJoinedByString: (OFString*)separator;















/*!
 * @brief Creates a string by calling the selector on all objects of the array
 *	  and joining the strings returned by calling the selector.
 *
 * @param separator The string with which the objects should be joined
 * @param selector The selector to perform on the objects
 * @return A string containing all objects joined by the separator
 */
- (OFString*)componentsJoinedByString: (OFString*)separator
			usingSelector: (SEL)selector;


















/*!
 * @brief Performs the specified selector on all objects in the array.
 *
 * @param selector The selector to perform on all objects in the array
 */
- (void)makeObjectsPerformSelector: (SEL)selector;








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











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







265
266
267
268
269
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
308
309
310
311
312
313
314
315
316
317
318
319
320
 * @brief Creates a string by joining all objects of the array.
 *
 * @param separator The string with which the objects should be joined
 * @return A string containing all objects joined by the separator
 */
- (OFString*)componentsJoinedByString: (OFString*)separator;

/*!
 * @brief Creates a string by joining all objects of the array.
 *
 * @param separator The string with which the objects should be joined
 * @param options Options according to which the objects should be joined.@n
 *		  Possible values are:
 *		  Value                | Description
 *		  ---------------------|----------------------
 * 		  OF_ARRAY_SKIP_EMPTY | Skip empty components
 * @return A string containing all objects joined by the separator
 */
- (OFString*)componentsJoinedByString: (OFString*)separator
			      options: (int)options;

/*!
 * @brief Creates a string by calling the selector on all objects of the array
 *	  and joining the strings returned by calling the selector.
 *
 * @param separator The string with which the objects should be joined
 * @param selector The selector to perform on the objects
 * @return A string containing all objects joined by the separator
 */
- (OFString*)componentsJoinedByString: (OFString*)separator
			usingSelector: (SEL)selector;

/*!
 * @brief Creates a string by calling the selector on all objects of the array
 *	  and joining the strings returned by calling the selector.
 *
 * @param separator The string with which the objects should be joined
 * @param selector The selector to perform on the objects
 * @param options Options according to which the objects should be joined.@n
 *		  Possible values are:
 *		  Value                | Description
 *		  ---------------------|----------------------
 * 		  OF_ARRAY_SKIP_EMPTY | Skip empty components
 * @return A string containing all objects joined by the separator
 */
- (OFString*)componentsJoinedByString: (OFString*)separator
			usingSelector: (SEL)selector
			      options: (int)options;

/*!
 * @brief Performs the specified selector on all objects in the array.
 *
 * @param selector The selector to perform on all objects in the array
 */
- (void)makeObjectsPerformSelector: (SEL)selector;

305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
- (OFArray*)sortedArray;

/*!
 * @brief Returns a sorted copy of the array.
 *
 * @param options The options to use when sorting the array.@n
 *		  Possible values are:
 *		  Value                      | Description
 *		  ---------------------------|-------------------------
 *		  OF_SORT_OPTIONS_DESCENDING | Sort in descending order
 * @return A sorted copy of the array
 */
- (OFArray*)sortedArrayWithOptions: (int)options;

/*!
 * @brief Returns a copy of the array with the order reversed.
 *







|
|
|







337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
- (OFArray*)sortedArray;

/*!
 * @brief Returns a sorted copy of the array.
 *
 * @param options The options to use when sorting the array.@n
 *		  Possible values are:
 *		  Value                    | Description
 *		  -------------------------|-------------------------
 *		  OF_ARRAY_SORT_DESCENDING | Sort in descending order
 * @return A sorted copy of the array
 */
- (OFArray*)sortedArrayWithOptions: (int)options;

/*!
 * @brief Returns a copy of the array with the order reversed.
 *

Modified src/OFArray.m from [5e48577b79] to [38f8d86997].

394
395
396
397
398
399
400
401

















402
403
404
405

406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428















429
430
431
432
433
434
435
436
437
438
439

440
441
442
443
444
445
446

	return ret;
}

- (OFString*)componentsJoinedByString: (OFString*)separator
{
	return [self componentsJoinedByString: separator
				usingSelector: @selector(description)];

















}

- (OFString*)componentsJoinedByString: (OFString*)separator
			usingSelector: (SEL)selector

{
	void *pool;
	OFMutableString *ret;
	id *objects;
	size_t i, count;
	IMP append;

	if (separator == nil)
		@throw [OFInvalidArgumentException exception];

	count = [self count];

	if (count == 0)
		return @"";
	if (count == 1)
		return [[self firstObject] performSelector: selector];

	ret = [OFMutableString string];
	append = [ret methodForSelector: @selector(appendString:)];

	pool = objc_autoreleasePoolPush();
	objects = [self objects];
















	for (i = 0; i < count - 1; i++) {
		void *pool2 = objc_autoreleasePoolPush();

		append(ret, @selector(appendString:),
		    [objects[i] performSelector: selector]);
		append(ret, @selector(appendString:), separator);

		objc_autoreleasePoolPop(pool2);
	}
	append(ret, @selector(appendString:),
	    [objects[i] performSelector: selector]);


	[ret makeImmutable];

	objc_autoreleasePoolPop(pool);

	return ret;
}







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




>





<












<




>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|

|
|
|

|
|
<
|
>







394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428

429
430
431
432
433
434
435
436
437
438
439
440

441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468

469
470
471
472
473
474
475
476
477

	return ret;
}

- (OFString*)componentsJoinedByString: (OFString*)separator
{
	return [self componentsJoinedByString: separator
				usingSelector: @selector(description)
				      options: 0];
}

- (OFString*)componentsJoinedByString: (OFString*)separator
			      options: (int)options
{
	return [self componentsJoinedByString: separator
				usingSelector: @selector(description)
				      options: options];
}

- (OFString*)componentsJoinedByString: (OFString*)separator
			usingSelector: (SEL)selector
{
	return [self componentsJoinedByString: separator
				usingSelector: selector
				      options: 0];
}

- (OFString*)componentsJoinedByString: (OFString*)separator
			usingSelector: (SEL)selector
			      options: (int)options
{
	void *pool;
	OFMutableString *ret;
	id *objects;
	size_t i, count;


	if (separator == nil)
		@throw [OFInvalidArgumentException exception];

	count = [self count];

	if (count == 0)
		return @"";
	if (count == 1)
		return [[self firstObject] performSelector: selector];

	ret = [OFMutableString string];


	pool = objc_autoreleasePoolPush();
	objects = [self objects];

	if (options & OF_ARRAY_SKIP_EMPTY) {
		for (i = 0; i < count; i++) {
			void *pool2 = objc_autoreleasePoolPush();
			OFString *component =
			    [objects[i] performSelector: selector];

			if ([component length] > 0) {
				if ([ret length] > 0)
					[ret appendString: separator];
				[ret appendString: component];
			}

			objc_autoreleasePoolPop(pool2);
		}
	} else {
		for (i = 0; i < count - 1; i++) {
			void *pool2 = objc_autoreleasePoolPush();

			[ret appendString:
			    [objects[i] performSelector: selector]];
			[ret appendString: separator];

			objc_autoreleasePoolPop(pool2);
		}

		[ret appendString: [objects[i] performSelector: selector]];
	}

	[ret makeImmutable];

	objc_autoreleasePoolPop(pool);

	return ret;
}

Modified src/OFMutableArray.m from [20e48ccd57] to [fce85c3ce9].

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
@end

static void
quicksort(OFMutableArray *array, size_t left, size_t right, int options)
{
	of_comparison_result_t ascending, descending;

	if (options & OF_SORT_OPTIONS_DESCENDING) {
		ascending = OF_ORDERED_DESCENDING;
		descending = OF_ORDERED_ASCENDING;
	} else {
		ascending = OF_ORDERED_ASCENDING;
		descending = OF_ORDERED_DESCENDING;
	}








|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
@end

static void
quicksort(OFMutableArray *array, size_t left, size_t right, int options)
{
	of_comparison_result_t ascending, descending;

	if (options & OF_ARRAY_SORT_DESCENDING) {
		ascending = OF_ORDERED_DESCENDING;
		descending = OF_ORDERED_ASCENDING;
	} else {
		ascending = OF_ORDERED_ASCENDING;
		descending = OF_ORDERED_DESCENDING;
	}

Modified tests/OFArrayTests.m from [c4b233b4a6] to [007d7f7189].

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172






173
174
175
176
177
178
179

	m[1] = [[a[0] mutableCopy] autorelease];
	[m[1] addObject: @"0"];
	[m[1] addObject: @"z"];
	TEST(@"-[sortedArray]",
	    [[m[1] sortedArray] isEqual: ([OFArray arrayWithObjects:
	    @"0", @"Bar", @"Baz", @"Foo", @"z", nil])] &&
	    [[m[1] sortedArrayWithOptions: OF_SORT_OPTIONS_DESCENDING]
	    isEqual: ([OFArray arrayWithObjects:
	    @"z", @"Foo", @"Baz", @"Bar", @"0", nil])])

	EXPECT_EXCEPTION(@"Detect out of range in -[objectAtIndex:]",
	    OFOutOfRangeException, [a[0] objectAtIndex: [a[0] count]])

	EXPECT_EXCEPTION(@"Detect out of range in -[removeObjectsInRange:]",
	    OFOutOfRangeException, [m[0] removeObjectsInRange:
		of_range(0, [m[0] count] + 1)])

	TEST(@"-[componentsJoinedByString:]",
	    (a[1] = [OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil]) &&
	    [[a[1] componentsJoinedByString: @" "] isEqual: @"foo bar baz"] &&
	    (a[1] = [OFArray arrayWithObject: @"foo"]) &&
	    [[a[1] componentsJoinedByString: @" "] isEqual: @"foo"])







	m[0] = [[a[0] mutableCopy] autorelease];
	ok = true;
	i = 0;

	TEST(@"-[objectEnumerator]", (enumerator = [m[0] objectEnumerator]))








|















>
>
>
>
>
>







150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

	m[1] = [[a[0] mutableCopy] autorelease];
	[m[1] addObject: @"0"];
	[m[1] addObject: @"z"];
	TEST(@"-[sortedArray]",
	    [[m[1] sortedArray] isEqual: ([OFArray arrayWithObjects:
	    @"0", @"Bar", @"Baz", @"Foo", @"z", nil])] &&
	    [[m[1] sortedArrayWithOptions: OF_ARRAY_SORT_DESCENDING]
	    isEqual: ([OFArray arrayWithObjects:
	    @"z", @"Foo", @"Baz", @"Bar", @"0", nil])])

	EXPECT_EXCEPTION(@"Detect out of range in -[objectAtIndex:]",
	    OFOutOfRangeException, [a[0] objectAtIndex: [a[0] count]])

	EXPECT_EXCEPTION(@"Detect out of range in -[removeObjectsInRange:]",
	    OFOutOfRangeException, [m[0] removeObjectsInRange:
		of_range(0, [m[0] count] + 1)])

	TEST(@"-[componentsJoinedByString:]",
	    (a[1] = [OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil]) &&
	    [[a[1] componentsJoinedByString: @" "] isEqual: @"foo bar baz"] &&
	    (a[1] = [OFArray arrayWithObject: @"foo"]) &&
	    [[a[1] componentsJoinedByString: @" "] isEqual: @"foo"])

	TEST(@"-[componentsJoinedByString:options]",
	    (a[1] = [OFArray arrayWithObjects: @"", @"foo", @"", @"", @"bar",
	    @"", nil]) && [[a[1] componentsJoinedByString: @" "
						  options: OF_ARRAY_SKIP_EMPTY]
	    isEqual: @"foo bar"])

	m[0] = [[a[0] mutableCopy] autorelease];
	ok = true;
	i = 0;

	TEST(@"-[objectEnumerator]", (enumerator = [m[0] objectEnumerator]))