From 4b3bd1aa90162a2816d2eef156fea32511a1e0a5 Mon Sep 17 00:00:00 2001 From: Hugo Melder Date: Fri, 13 Dec 2024 03:01:07 -0800 Subject: [PATCH] NSPointerArray: Implement fast enumeration (#477) * NSPointerArray: Implement NSFastEnumeration * NSPointerArray: Test for duplicate values in array * NSPointerArray: Fast enumeration tests --- Headers/Foundation/NSPointerArray.h | 2 +- Source/NSPointerArray.m | 28 ++++++++++++++ Tests/base/NSPointerArray/create.m | 4 +- Tests/base/NSPointerArray/iterate.m | 57 +++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 Tests/base/NSPointerArray/iterate.m diff --git a/Headers/Foundation/NSPointerArray.h b/Headers/Foundation/NSPointerArray.h index caab35293b..108dd3d4e9 100644 --- a/Headers/Foundation/NSPointerArray.h +++ b/Headers/Foundation/NSPointerArray.h @@ -42,7 +42,7 @@ extern "C" { * or grow (adding nil/zero items). */ GS_EXPORT_CLASS -@interface NSPointerArray : NSObject +@interface NSPointerArray : NSObject /** Allocate an instance, initialise using initWithOptions: and * return it autoreleased. diff --git a/Source/NSPointerArray.m b/Source/NSPointerArray.m index 84d2978648..7a2c20053d 100644 --- a/Source/NSPointerArray.m +++ b/Source/NSPointerArray.m @@ -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) diff --git a/Tests/base/NSPointerArray/create.m b/Tests/base/NSPointerArray/create.m index 5af2c0b7b8..ea0275f34e 100644 --- a/Tests/base/NSPointerArray/create.m +++ b/Tests/base/NSPointerArray/create.m @@ -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 diff --git a/Tests/base/NSPointerArray/iterate.m b/Tests/base/NSPointerArray/iterate.m new file mode 100644 index 0000000000..9df8bcb7d5 --- /dev/null +++ b/Tests/base/NSPointerArray/iterate.m @@ -0,0 +1,57 @@ +#import "ObjectTesting.h" +#import +#import + +#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 +