blob: ccce557482fb99532cf1328c94758780d4ceccbc [file] [log] [blame]
/* Test basic Objective-C foreach syntax. This tests iterations, with
the basic syntax 'for (object in array) statements'
*/
/* { dg-do run } */
/* { dg-skip-if "No NeXT fast enum. pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */
/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
/* { dg-options "-mno-constant-cfstrings" { target *-*-darwin* } } */
/* { dg-additional-sources "../objc-obj-c++-shared/nsconstantstring-class-impl.m" } */
/* { dg-additional-options "-Wno-objc-root-class" } */
#include "../objc-obj-c++-shared/TestsuiteObject.m"
#ifndef __NEXT_RUNTIME__
#include <objc/NXConstStr.h>
#else
#include "../objc-obj-c++-shared/nsconstantstring-class.h"
#endif
extern int printf (const char *, ...);
#include <stdlib.h>
/*
struct __objcFastEnumerationState
{
unsigned long state;
id *itemsPtr;
unsigned long *mutationsPtr;
unsigned long extra[5];
};
*/
/* A mini-array implementation that can be used to test fast
enumeration. You create the array with some objects; you can
mutate the array, and you can fast-enumerate it.
*/
@interface MyArray : TestsuiteObject
{
unsigned int length;
id *objects;
unsigned long mutated;
}
- (id) initWithLength: (unsigned int)l objects: (id *)o;
- (void) mutate;
- (unsigned long)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state
objects:(id *)stackbuf
count:(unsigned long)len;
@end
@implementation MyArray : TestsuiteObject
- (id) initWithLength: (unsigned int)l
objects: (id *)o
{
length = l;
objects = o;
mutated = 0;
return self;
}
- (void) mutate
{
mutated = 1;
}
- (unsigned long)countByEnumeratingWithState: (struct __objcFastEnumerationState*)state
objects: (id*)stackbuf
count: (unsigned long)len
{
unsigned long i, batch_size;
/* We keep how many objects we served in the state->state counter. So the next batch
will contain up to length - state->state objects. */
batch_size = length - state->state;
/* Make obvious adjustments. */
if (batch_size < 0)
batch_size = 0;
if (batch_size > len)
batch_size = len;
/* Copy the objects. */
for (i = 0; i < batch_size; i++)
stackbuf[i] = objects[i];
state->state += batch_size;
state->itemsPtr = stackbuf;
state->mutationsPtr = &mutated;
return batch_size;
}
@end
int main (void)
{
MyArray *array;
TestsuiteObject *object;
int test_variable, counter, i;
id *objects;
array = [[MyArray alloc] initWithLength: 0
objects: NULL];
/* Test that an empty array does nothing. */
for (object in array)
abort ();
if (object != nil)
abort ();
/* Test iterating over 1 object. */
objects = malloc (sizeof (id) * 1);
objects[0] = @"One Object";
array = [[MyArray alloc] initWithLength: 1
objects: objects];
for (object in array)
printf ("%p\n", object);
/* Test iterating over 20 objects. */
objects = malloc (sizeof (id) * 20);
for (i = 0; i < 20; i++)
objects[i] = @"object";
array = [[MyArray alloc] initWithLength: 20
objects: objects];
for (object in array)
printf ("%p\n", object);
/* Test iterating over 200 objects. */
objects = malloc (sizeof (id) * 200);
for (i = 0; i < 200; i++)
objects[i] = @"object";
array = [[MyArray alloc] initWithLength: 200
objects: objects];
counter = 0;
for (object in array)
{
if (object != nil)
counter++;
}
if (counter != 200)
abort ();
printf ("Counter was %d (should be 200)\n", counter);
/* Test iterating again over the same array. */
counter = 0;
for (object in array)
{
if (object != nil)
counter++;
}
if (counter != 200)
abort ();
printf ("Counter was %d (should be 200)\n", counter);
/* Test nested iterations. */
objects = malloc (sizeof (id) * 20);
for (i = 0; i < 20; i++)
objects[i] = @"object";
array = [[MyArray alloc] initWithLength: 20
objects: objects];
counter = 0;
for (object in array)
{
id another_object;
for (another_object in array)
if (another_object != nil)
counter++;
}
printf ("Counter was %d (should be 400)\n", counter);
if (counter != 400)
abort ();
/* Test 'continue'. */
objects = malloc (sizeof (id) * 20);
for (i = 0; i < 20; i++)
objects[i] = @"object";
array = [[MyArray alloc] initWithLength: 20
objects: objects];
counter = 0;
for (object in array)
{
if (counter == 15)
continue;
counter++;
}
printf ("Counter was %d (should be 15)\n", counter);
if (counter != 15)
abort ();
/* Test 'break'. */
objects = malloc (sizeof (id) * 20);
for (i = 0; i < 20; i++)
objects[i] = @"object";
array = [[MyArray alloc] initWithLength: 20
objects: objects];
counter = 0;
for (object in array)
{
counter++;
if (counter == 15)
break;
}
printf ("Counter was %d (should be 15)\n", counter);
if (counter != 15)
abort ();
/* Test 'break' and 'continue' in nested iterations. */
objects = malloc (sizeof (id) * 20);
for (i = 0; i < 20; i++)
objects[i] = @"object";
array = [[MyArray alloc] initWithLength: 20
objects: objects];
counter = 0;
for (object in array)
{
int local_counter = 0;
id another_object;
/* Each internal loop should increase counter by 24. */
for (another_object in array)
{
local_counter++;
if (local_counter == 10)
{
counter = counter + 20;
break;
}
if (local_counter >= 5)
continue;
counter++;
}
/* Exit after 4 iterations. */
if (counter == 96)
break;
}
printf ("Counter was %d (should be 96)\n", counter);
if (counter != 96)
abort ();
/* Test that if we 'break', the object is set to the last one, while
if we run out of objects, it is set to 'nil'. */
for (object in array)
;
if (object != nil)
abort ();
for (object in array)
break;
if (object == nil)
abort ();
/* Test that C for loops still work. */
test_variable = 0;
for (counter = 0; counter < 4; counter++)
test_variable++;
if (test_variable != 4)
abort ();
return 0;
}