Skip to content

Commit

Permalink
NSPointerArray: Implement fast enumeration (#477)
Browse files Browse the repository at this point in the history
* NSPointerArray: Implement NSFastEnumeration

* NSPointerArray: Test for duplicate values in array

* NSPointerArray: Fast enumeration tests
  • Loading branch information
hmelder authored Dec 13, 2024
1 parent 4a4a802 commit 4b3bd1a
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Headers/Foundation/NSPointerArray.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ extern "C" {
* or grow (adding nil/zero items).
*/
GS_EXPORT_CLASS
@interface NSPointerArray : NSObject <NSCopying, NSCoding>
@interface NSPointerArray : NSObject <NSCoding, NSCopying, NSFastEnumeration>

/** Allocate an instance, initialise using initWithOptions: and
* return it autoreleased.
Expand Down
28 changes: 28 additions & 0 deletions Source/NSPointerArray.m
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,34 @@ - (void) setCount: (NSUInteger)count
[self subclassResponsibility: _cmd];
}

- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (__unsafe_unretained id[])stackbuf
count: (NSUInteger)len
{
NSInteger count;

state->mutationsPtr = (unsigned long *)&state->mutationsPtr;
count = MIN(len, [self count] - state->state);
if (count > 0)
{
IMP imp = [self methodForSelector: @selector(pointerAtIndex:)];
int p = state->state;
int i;

for (i = 0; i < count; i++, p++)
{
stackbuf[i] = (*imp)(self, @selector(pointerAtIndex:), p);
}
state->state += count;
}
else
{
count = 0;
}
state->itemsPtr = stackbuf;
return count;
}

@end

@implementation NSPointerArray (NSArrayConveniences)
Expand Down
4 changes: 3 additions & 1 deletion Tests/base/NSPointerArray/create.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ int main()
PASS([obj count] == 1, "+addPointer: increments count");
[obj addPointer: nil];
PASS([obj count] == 2, "+addPointer: works with nil");
[obj addPointer: nil];
PASS([obj count] == 3, "+addPointer: respects duplicate values");

[obj insertPointer: (void*)vals[0] atIndex: 0];
[obj insertPointer: (void*)vals[1] atIndex: 0];
[obj insertPointer: (void*)vals[2] atIndex: 0];
PASS([obj count] == 5 && [obj pointerAtIndex: 2] == (void*)vals[0],
PASS([obj count] == 6 && [obj pointerAtIndex: 2] == (void*)vals[0],
"+insertPointer:atIndex: works");

LEAVE_POOL
Expand Down
57 changes: 57 additions & 0 deletions Tests/base/NSPointerArray/iterate.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#import "ObjectTesting.h"
#import <Foundation/NSPointerArray.h>
#import <Foundation/NSAutoreleasePool.h>

#if defined(__clang__)

int main()
{
ENTER_POOL
NSPointerArray *obj = AUTORELEASE([NSPointerArray new]);
NSString *str = @"test";
NSString *str2 = @"string";

// Fast iteration over empty pointer array
for (id ptr in obj) {
PASS(0, "No element returned by fast iteration");
}

[obj addPointer: str];
[obj addPointer: str2];
[obj addPointer: nil];
[obj addPointer: nil];

int count = 0;
for (id ptr in obj) {
count += 1;
switch (count) {
case 1:
PASS(ptr == str, "first obj returned is pointer to 'test'");
break;
case 2:
PASS(ptr == str2, "second obj returned is pointer to 'string'");
break;
case 3:
case 4:
PASS(ptr == nil, "third and fourth pointers are nil");
break;
default:
PASS(0, "unexpected count of pointers");
}
}
PASS(count == 4, "got 4 pointers in fast iteration");

LEAVE_POOL

return 0;
}

#else

int main()
{
return 0;
}

#endif

0 comments on commit 4b3bd1a

Please sign in to comment.