This is Collection.m in view mode; [Download] [Up]
/* Implementation for Objective-C Collection object
Copyright (C) 1993 R. Andrew McCallum <mccallum@cs.rochester.edu>
Dept. of Computer Science, U. of Rochester, Rochester, NY 14627
This file is part of the GNU Objective-C Collection library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <coll/Collection.h>
#include <coll/CollectionPrivate.h>
#include <objc/objc-api.h>
#include <stdio.h> /* for vfprintf() in "-warning:" */
#include <stdarg.h>
const elt COLL_NO_ELEMENT = ((elt)(~0L));
/* I'd like this to be made public */
int
objc_sizeof_type(const char* type)
{
switch(*type) {
case _C_ID: return sizeof(id);
break;
case _C_CLASS:
return sizeof(Class*);
break;
case _C_SEL:
return sizeof(SEL);
break;
case _C_CHR:
return sizeof(char);
break;
case _C_UCHR:
return sizeof(unsigned char);
break;
case _C_SHT:
return sizeof(short);
break;
case _C_USHT:
return sizeof(unsigned short);
break;
case _C_INT:
case _C_LNG:
return sizeof(int);
break;
case _C_UINT:
case _C_ULNG:
return sizeof(unsigned int);
break;
case _C_ATOM:
case _C_CHARPTR:
return sizeof(char*);
break;
default:
fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
abort();
}
}
@implementation Collection
+ initialize
{
if (self == [Collection class])
{
/* This should be checked at compile time. Why do I get a parse
error when I use sizeof() in a #if () statement? */
if (sizeof(elt) != sizeof(void*))
[self error:"(sizeof(elt) == sizeof(void*)) not satisfied"];
[self setVersion:-1]; /* alpha release */
}
return self;
}
// INITIALIZING AND FREEING;
/* This is the designated initializer of this class */
- initDescription:(const char *)type
{
[super init];
if (objc_sizeof_type(type) > sizeof(elt))
[self error:
"Collection can't store elements with size greater than (elt)"];
OBJC_MALLOC(_description, char, strlen(type)+1);
strcpy(_description, type);
/* This is not portable... Change this switch. */
switch (*_description)
{
case _C_CHARPTR:
case _C_ATOM:
_compare_func = (compare_func_type)coll_compare_strings;
break;
case _C_ID:
case _C_CLASS: /* isEqual: on classes works well? */
_compare_func = (compare_func_type)coll_compare_objects;
break;
case _C_PTR:
case _C_SEL:
_compare_func = (compare_func_type)coll_compare_ptrs;
break;
case _C_INT:
case _C_UINT:
case _C_FLT: /* Yipes */
_compare_func = (compare_func_type)coll_compare_ints;
break;
case _C_LNG:
case _C_ULNG:
_compare_func = (compare_func_type)coll_compare_long_ints;
break;
default :
[self error:"Element type (%s) not supported.\n", _description];
}
return self;
}
- initDescription:(const char *)type with: (unsigned)numElements, ...
{
va_list ap;
[self initDescription:type];
va_start(ap, numElements);
// We should use objc_msg_lookup here?;
while (numElements--)
[self addElement:va_arg(ap, elt)];
va_end(ap);
return self;
}
- init
{
return [self initDescription:"@"];
}
- initWith: (unsigned)numElements, ...
{
va_list ap;
[self init];
va_start(ap, numElements);
// We should use objc_msg_lookup here?;
while (numElements--)
[self addElement:va_arg(ap, elt)];
va_end(ap);
return self;
}
- free
{
OBJC_FREE(_description);
return [super free];
}
- freeContents
{
if (CONTAINS_OBJECTS)
[self makeObjectsPerform:@selector(free)];
[self empty];
return self;
}
// ADDING;
- addElement: (elt)newElement
{
return [self subclassResponsibility:_cmd];
}
- addElementIfAbsent: (elt)newElement
{
if (![self includesElement:newElement])
return [self addElement:newElement];
return nil;
}
- addContentsOf: (id <Collecting>)aCollection
{
id (*addElementImp)(id,SEL,elt) = (id(*)(id,SEL,elt))
objc_msg_lookup(self, @selector(addElement:));
/* Should all these doIt()'s be 'static inline' ? */
void doIt(elt e)
{
addElementImp(self, @selector(addElement:), e);
}
[aCollection withElementsCall:doIt];
return self;
}
- addContentsOfIfAbsent: (id <Collecting>)aCollection
{
id (*addElementImp)(id,SEL,elt) = (id(*)(id,SEL,elt))
objc_msg_lookup(self, @selector(addElement:));
BOOL (*includesElementImp)(id,SEL,elt) = (BOOL(*)(id,SEL,elt))
objc_msg_lookup(self, @selector(includesElement:));
void doIt(elt e)
{
if (!includesElementImp(self, @selector(includesElement), e))
addElementImp(self, @selector(addElement:), e);
}
[aCollection withElementsCall:doIt];
return self;
}
- addCount: (unsigned)count, ...
{
va_list ap;
va_start(ap, count);
while (count--)
[self addElement:va_arg(ap, elt)];
va_end(ap);
return self;
}
// REMOVING AND REPLACING;
- (elt) removeElement: (elt)oldElement
{
return [self subclassResponsibility:_cmd];
}
- (elt ) removeAllOccurrencesOfElement: (elt )oldElement
{
elt r;
BOOL (*includesElementImp)(id,SEL,elt) = (BOOL(*)(id,SEL,elt))
objc_msg_lookup(self, @selector(includesElement:));
elt (*removeElementImp)(id,SEL,elt) = (elt(*)(id,SEL,elt))
objc_msg_lookup(self, @selector(removeElement:));
while (includesElementImp(self, @selector(includesElement:), oldElement))
{
r = removeElementImp(self, @selector(removeElement:), oldElement);
}
return r;
}
- removeContentsIn: (id <Collecting>)aCollection
{
BOOL (*includesElementImp)(id,SEL,elt) = (BOOL(*)(id,SEL,elt))
objc_msg_lookup(self, @selector(includesElement:));
elt (*removeElementImp)(id,SEL,elt) = (elt(*)(id,SEL,elt))
objc_msg_lookup(self, @selector(removeElement:));
void doIt(elt e)
{
if (includesElementImp(self, @selector(includesElement:), e))
removeElementImp(self, @selector(removeElement:), e);
}
[aCollection withElementsCall:doIt];
return self;
}
- removeContentsNotIn: (id <Collecting>)aCollection
{
BOOL (*includesElementImp)(id,SEL,elt) = (BOOL(*)(id,SEL,elt))
objc_msg_lookup(aCollection, @selector(includesElement:));
elt (*removeElementImp)(id,SEL,elt) = (elt(*)(id,SEL,elt))
objc_msg_lookup(self, @selector(removeElement:));
void doIt(elt e)
{
if (!includesElementImp(aCollection, @selector(includesElement:), e))
removeElementImp(self, @selector(removeElement:), e);
}
[self withElementsCall:doIt];
return self;
}
/* remember this has to be overridden for IndexedCollection's */
- (elt) replaceElement: (elt )oldElement with: (elt )newElement
{
elt ret;
ret = [self removeElement:oldElement];
[self addElement:newElement];
return ret;
}
- (elt) replaceAllOccurrencesOfElement: (elt)oldElement with: (elt)newElement
{
elt ret;
// Use objc_msg_lookup here also;
if (_compare_func(oldElement.void_ptr_t, newElement.void_ptr_t))
return self;
while ([self includesElement:oldElement])
ret = [self replaceElement:oldElement with:newElement];
return ret;
}
- uniqueContents
{
// Use objc_msg_lookup here also;
void doIt(elt e)
{
while ([self occurrencesOfElement:e] > 1)
[self removeElement:e];
}
[self withElementsCall:doIt];
return self;
}
- empty
{
// Use objc_msg_lookup here also;
void doIt(elt e)
{
[self removeElement:e];
}
[[[self shallowCopy] withElementsCall:doIt] free];
return self;
}
// TESTING;
- (BOOL) isEmpty
{
return ([self count] == 0);
}
/* Potentially inefficient, may be overridden in subclasses */
- (BOOL) includesElement: (elt)anElement
{
BOOL test(elt e)
{
if (_compare_func(anElement.void_ptr_t, e.void_ptr_t))
return YES;
else
return NO;
}
return [self trueForAnyByCalling:test];
}
- (BOOL) includesSubsetOf: (id <Collecting>)aCollection
{
BOOL test(elt e)
{
return [self includesElement:e];
}
return [aCollection trueForAllByCalling:test];
}
- (BOOL) includesSameContents: (id <Collecting>)aCollection
{
// not very efficient;
return ([self includesSubsetOf:aCollection] &&
[aCollection includesSubsetOf:self]);
}
/* Is this what we want? */
- (BOOL) isEqual: anObject
{
if ([self class] == [anObject class] &&
[self includesSameContents: anObject])
return YES;
else
return NO;
}
- (BOOL) isDisjointFrom: (id <Collecting>)aCollection
{
// Use objc_msg_lookup here also;
BOOL flag = YES;
void doIt(elt e)
{
if (![aCollection includesElement:e])
flag = NO;
}
[self withElementsCall:doIt whileTrue:&flag];
return !flag;
}
- (BOOL) trueForAllByCalling: (BOOL(*)(elt))aFunc
{
BOOL flag = YES;
void doIt(elt e)
{
if (!(aFunc(e)))
flag = NO;
}
[self withElementsCall:doIt whileTrue:&flag];
return flag;
}
- (BOOL) trueForAnyByCalling: (BOOL(*)(elt))aFunc;
{
BOOL flag = YES;
void doIt(elt e)
{
if (aFunc(e))
flag = NO;
}
[self withElementsCall:doIt whileTrue:&flag];
return !flag;
}
/* Inefficient, so should be overridden in subclasses. */
- (unsigned) count
{
unsigned n = 0;
void doIt(elt e)
{
n++;
}
[self withElementsCall:doIt];
return n;
}
- (unsigned) occurrencesOfElement: (elt)anElement
{
unsigned count = 0;
void doIt(elt e)
{
if (_compare_func(anElement.void_ptr_t, e.void_ptr_t))
count++;
}
[self withElementsCall:doIt];
return count;
}
- (unsigned) occurrencesOfObject: anObject
{
return [self occurrencesOfElement:anObject];
}
- (const char *) contentsDescription
{
return _description;
}
- (BOOL) containsObjects
{
return CONTAINS_OBJECTS;
}
// ENUMERATING;
- (BOOL) getNextElement:(elt *)anElementPtr withEnumState: (void**)enumState
{
[self subclassResponsibility:_cmd];
return NO;
}
/* Getting objects one at a time. Pass NULL enumState to start.
It will return COLL_NO_ELEMENT when done. */
- nextObject: (void**)enumState
{
elt o;
if ([self getNextElement:&o withEnumState:enumState])
return o.id_t;
else
return COLL_NO_OBJECT;
}
- withElementsCall: (void(*)(elt))aFunc whileTrue:(BOOL *)flag
{
void *enumState = 0;
elt e;
while (*flag && [self getNextElement:&e withEnumState:&enumState])
aFunc(e);
return self;
}
- withElementsCall: (void(*)(elt))aFunc
{
BOOL flag = YES;
return [self withElementsCall:aFunc whileTrue:&flag];
}
// COPYING;
- shallowCopy
{
return [self shallowCopyAs:[self species]];
}
/* the copy to be filled by -shallowCopySelect, -shallowCopyCollect, etc... */
- emptyCopyAs: aCollectionClass
{
return [[aCollectionClass alloc] initDescription:_description];
}
/* the right thing for ordered objects also? */
- shallowCopyAs: (id <Collecting>)aCollectionClass
{
id newColl = [self emptyCopyAs:aCollectionClass];
id (*addElementImp)(id,SEL,elt) = (id(*)(id,SEL,elt))
objc_msg_lookup(newColl, @selector(addElement:));
void doIt(elt e)
{
addElementImp(newColl, @selector(addElement:), e);
}
[self withElementsCall:doIt];
return newColl;
}
- deepen
{
/* could use objc_msg_lookup here too */
void doIt(elt o)
{
[self replaceElement:o with:[[o.id_t shallowCopy] deepen]];
}
if (OBJECTS_REQUIRED_WARNING())
return self;
/* Is this shallowCopy necessary? I think so, unfortunately. */
[[[self shallowCopy] withElementsCall:doIt] free];
return self;
}
- species
{
return [self class];
}
// COPYING ENUMERATORS;
- shallowCopySelectByCalling: (BOOL(*)(elt))aFunc
{
id newColl = [self emptyCopyAs:[self species]];
id (*addElementImp)(id,SEL,elt) = (id(*)(id,SEL,elt))
objc_msg_lookup(newColl, @selector(addElement:));
void doIt(elt e)
{
if (aFunc(e))
addElementImp(newColl, @selector(addElement:), e);
}
[self withElementsCall:doIt];
return newColl;
}
- shallowCopyRejectByCalling: (BOOL(*)(elt))aFunc
{
id newColl = [self emptyCopyAs:[self species]];
id (*addElementImp)(id,SEL,elt) = (id(*)(id,SEL,elt))
objc_msg_lookup(newColl, @selector(addElement:));
void doIt(elt e)
{
if (!aFunc(e))
addElementImp(newColl, @selector(addElement:), e);
}
return newColl;
}
- shallowCopyCollectByCalling: (elt (*)(elt))aFunc
{
id newColl = [self emptyCopyAs:[self species]];
id (*addElementImp)(id,SEL,elt) = (id(*)(id,SEL,elt))
objc_msg_lookup(newColl, @selector(addElement:));
void doIt(elt e)
{
addElementImp(newColl, @selector(addElement:), aFunc(e));
}
return newColl;
}
// NON-COPYING ENUMERATORS;
- (elt ) detectElementByCalling: (BOOL(*)(elt))aFunc
{
BOOL flag = YES;
elt detectedElement;
void doIt(elt e)
{
if (aFunc(e)) {
flag = NO;
detectedElement = e;
}
}
detectedElement = COLL_NO_ELEMENT;
[self withElementsCall:doIt whileTrue:&flag];
return detectedElement;
}
- (elt) maxElementByCalling: (int(*)(elt,elt))aFunc
{
elt max;
BOOL firstTime = YES;
void doIt(elt e)
{
if (firstTime)
{
firstTime = NO;
max = e;
}
else
{
if (aFunc(e,max) > 0)
max = e;
}
}
[self withElementsCall:doIt];
return max;
}
- (elt) minElementByCalling: (int(*)(elt,elt))aFunc
{
elt min;
BOOL firstTime = YES;
void doIt(elt e)
{
if (firstTime)
{
firstTime = NO;
min = e;
}
else
{
if (aFunc(e,min) < 0)
min = e;
}
}
[self withElementsCall:doIt];
return min;
}
- inject: (void*)initialData byCalling: (void* (*)(void*,elt))aFunc
{
void doIt(elt e)
{
initialData = aFunc(initialData, e);
}
[self withElementsCall:doIt];
return self;
}
// SMALLTALK BLOCKS AS SELECTORS;
- (BOOL) trueForAllByPerforming: (SEL)aBoolSel in: selObject
{
BOOL (*aBoolSelImp)(id,SEL,id) = (BOOL(*)(id,SEL,id))
objc_msg_lookup(selObject, aBoolSel);
BOOL test(elt e)
{
return aBoolSelImp(selObject, aBoolSel, e.id_t);
}
if (OBJECTS_REQUIRED_WARNING())
return NO;
return [self trueForAllByCalling:test];
}
- (BOOL) trueForAllByPerforming: (SEL)aBoolSel in: selObject with: argObject
{
BOOL (*aBoolSelImp)(id,SEL,id,id) = (BOOL(*)(id,SEL,id,id))
objc_msg_lookup(selObject, aBoolSel);
BOOL test(elt e)
{
return aBoolSelImp(selObject, aBoolSel, e.id_t, argObject);
}
if (OBJECTS_REQUIRED_WARNING())
return NO;
return [self trueForAllByCalling:test];
}
- (BOOL) trueForAllByPerforming: (SEL)aBoolSel
{
BOOL test(elt e)
{
/* Is this the correct casting magic? */
return (unsigned)[e.id_t perform:aBoolSel];
}
if (OBJECTS_REQUIRED_WARNING())
return NO;
return [self trueForAllByCalling:test];
}
- (BOOL) trueForAllByPerforming: (SEL)aBoolSel with: argObject
{
BOOL test(elt e)
{
return (unsigned)[e.id_t perform:aBoolSel with:argObject];
}
if (OBJECTS_REQUIRED_WARNING())
return NO;
return [self trueForAllByCalling:test];
}
- (BOOL) trueForAnyByPerforming: (SEL)aBoolSel in: selObject
{
BOOL (*aBoolSelImp)(id,SEL,id) = (BOOL(*)(id,SEL,id))
objc_msg_lookup(selObject, aBoolSel);
BOOL test(elt e)
{
return aBoolSelImp(selObject, aBoolSel, e.id_t);
}
if (OBJECTS_REQUIRED_WARNING())
return NO;
return [self trueForAnyByCalling:test];
}
- (BOOL) trueForAnyByPerforming: (SEL)aBoolSel in: selObject with: argObject
{
BOOL (*aBoolSelImp)(id,SEL,id,id) = (BOOL(*)(id,SEL,id,id))
objc_msg_lookup(selObject, aBoolSel);
BOOL test(elt e)
{
return aBoolSelImp(selObject, aBoolSel, e.id_t, argObject);
}
if (OBJECTS_REQUIRED_WARNING())
return NO;
return [self trueForAnyByCalling:test];
}
- (BOOL) trueForAnyByPerforming: (SEL)aBoolSel
{
BOOL test(elt e)
{
return (unsigned)[e.id_t perform:aBoolSel];
}
if (OBJECTS_REQUIRED_WARNING())
return NO;
return [self trueForAnyByCalling:test];
}
- (BOOL) trueForAnyByPerforming: (SEL)aBoolSel with: argObject
{
BOOL test(elt e)
{
return (unsigned)[e.id_t perform:aBoolSel with:argObject];
}
if (OBJECTS_REQUIRED_WARNING())
return NO;
return [self trueForAnyByCalling:test];
}
- makeObjectsPerform: (SEL)aSel
{
void doIt(elt e)
{
[e.id_t perform:aSel];
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
[self withElementsCall:doIt];
return self;
}
- makeObjectsPerform: (SEL)aSel with: argObject
{
void doIt(elt e)
{
[e.id_t perform:aSel with:argObject];
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
[self withElementsCall:doIt];
return self;
}
- shallowCopySelectByPerforming: (SEL)aBoolSel in: selObject
{
BOOL (*aBoolSelImp)(id,SEL,id) = (BOOL(*)(id,SEL,id))
objc_msg_lookup(selObject, aBoolSel);
BOOL test(elt e)
{
return aBoolSelImp(selObject, aBoolSel, e.id_t);
}
return [self shallowCopySelectByCalling:test];
}
- shallowCopySelectByPerforming: (SEL)aBoolSel in: selObject with: argObject
{
BOOL (*aBoolSelImp)(id,SEL,id,id) = (BOOL(*)(id,SEL,id,id))
objc_msg_lookup(selObject, aBoolSel);
BOOL test(elt e)
{
return aBoolSelImp(selObject, aBoolSel, e.id_t, argObject);
}
return [self shallowCopySelectByCalling:test];
}
- shallowCopySelectByPerforming: (SEL)aBoolSel
{
BOOL test(elt e)
{
return (unsigned)[e.id_t perform:aBoolSel];
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self shallowCopySelectByCalling:test];
}
- shallowCopySelectByPerforming: (SEL)aBoolSel with: argObject
{
BOOL test(elt e)
{
return (unsigned)[e.id_t perform:aBoolSel with:argObject];
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self shallowCopySelectByCalling:test];
}
- shallowCopyRejectByPerforming: (SEL)aBoolSel in: selObject
{
BOOL (*aBoolSelImp)(id,SEL,id) = (BOOL(*)(id,SEL,id))
objc_msg_lookup(selObject, aBoolSel);
BOOL test(elt e)
{
return aBoolSelImp(selObject, aBoolSel, e.id_t);
}
return [self shallowCopyRejectByCalling:test];
}
- shallowCopyRejectByPerforming: (SEL)aBoolSel in: selObject with: argObject
{
BOOL (*aBoolSelImp)(id,SEL,id,id) = (BOOL(*)(id,SEL,id,id))
objc_msg_lookup(selObject, aBoolSel);
BOOL test(elt e)
{
return aBoolSelImp(selObject, aBoolSel, e.id_t, argObject);
}
return [self shallowCopyRejectByCalling:test];
}
- shallowCopyRejectByPerforming: (SEL)aBoolSel
{
BOOL test(elt e)
{
return (unsigned)[e.id_t perform:aBoolSel];
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self shallowCopyRejectByCalling:test];
}
- shallowCopyRejectByPerforming: (SEL)aBoolSel with: argObject
{
BOOL test(elt e)
{
return (unsigned)[e.id_t perform:aBoolSel with:argObject];
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self shallowCopyRejectByCalling:test];
}
- shallowCopyCollectByPerforming: (SEL)aSel in: selObject
{
id (*aSelImp)(id,SEL,id) = (id(*)(id,SEL,id))
objc_msg_lookup(selObject, aSel);
elt returnIt(elt e)
{
return (elt)aSelImp(selObject, aSel, e.id_t);
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self shallowCopyCollectByCalling:returnIt];
}
- shallowCopyCollectByPerforming: (SEL)aSel in: selObject with: argObject
{
id (*aSelImp)(id,SEL,id,id) = (id(*)(id,SEL,id,id))
objc_msg_lookup(selObject, aSel);
elt returnIt(elt e)
{
return (elt)aSelImp(selObject, aSel, e.id_t, argObject);
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self shallowCopyCollectByCalling:returnIt];
}
- shallowCopyCollectByPerforming: (SEL)aSel
{
elt returnIt(elt e)
{
return (elt)[e.id_t perform:aSel];
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self shallowCopyCollectByCalling:returnIt];
}
- shallowCopyCollectByPerforming: (SEL)aSel with: argObject
{
elt returnIt(elt e)
{
return (elt)[e.id_t perform:aSel with:argObject];
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self shallowCopyCollectByCalling:returnIt];
}
- detectByPerforming: (SEL)aBoolSel in: selObject
{
BOOL (*aBoolSelImp)(id,SEL,id) = (BOOL(*)(id,SEL,id))
objc_msg_lookup(selObject, aBoolSel);
BOOL test(id e)
{
return aBoolSelImp(selObject, aBoolSel, e);
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self detectObjectByCalling:test];
}
- detectByPerforming: (SEL)aBoolSel in: selObject with: argObject
{
BOOL (*aBoolSelImp)(id,SEL,id,id) = (BOOL(*)(id,SEL,id,id))
objc_msg_lookup(selObject, aBoolSel);
BOOL test(id e)
{
return aBoolSelImp(selObject, aBoolSel, e, argObject);
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self detectObjectByCalling:test];
}
- detectByPerforming: (SEL)aBoolSel
{
BOOL test(id e)
{
return (unsigned)[e perform:aBoolSel];
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self detectObjectByCalling:test];
}
- detectByPerforming: (SEL)aBoolSel with: argObject
{
BOOL test(id e)
{
return (unsigned)[e perform:aBoolSel with:argObject];
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self detectObjectByCalling:test];
}
- maxObjectByCalling: (int(*)(id,id))aFunc
{
id max;
BOOL firstTime = YES;
void doIt(id e)
{
if (firstTime)
{
firstTime = NO;
max = e;
}
else
{
if (aFunc(e,max) > 0)
max = e;
}
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
[self withObjectsCall:doIt];
return max;
}
- minObjectByCalling: (int(*)(id,id))aFunc
{
id min;
BOOL firstTime = YES;
void doIt(id e)
{
if (firstTime)
{
firstTime = NO;
min = e;
}
else
{
if (aFunc(e,min) < 0)
min = e;
}
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
[self withObjectsCall:doIt];
return min;
}
- maxByPerforming: (SEL)aSortingSel
{
int compare(id e1, id e2)
{
return (int)[e1 perform:aSortingSel with:e2];
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self maxObjectByCalling:compare];
}
- maxByPerforming: (SEL)aSortingSel in: selObject
{
int (*aSortingSelImp)(id,SEL,id,id) = (int(*)(id,SEL,id,id))
objc_msg_lookup(selObject, aSortingSel);
int compare(id e1, id e2)
{
return aSortingSelImp(selObject, aSortingSel, e1, e2);
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self maxObjectByCalling:compare];
}
- minByPerforming: (SEL)aSortingSel
{
int compare(id e1, id e2)
{
return (int)[e1 perform:aSortingSel with:e2];
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self minObjectByCalling:compare];
}
- minByPerforming: (SEL)aSortingSel in: selObject
{
int (*aSortingSelImp)(id,SEL,id,id) = (int(*)(id,SEL,id,id))
objc_msg_lookup(selObject, aSortingSel);
int compare(id e1, id e2)
{
return aSortingSelImp(selObject, aSortingSel, e1, e2);
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self minObjectByCalling:compare];
}
- inject: initialArgObject byPerforming: (SEL)aSel in: selObject
{
id (*aSelImp)(id,SEL,id,id) = (id(*)(id,SEL,id,id))
objc_msg_lookup(selObject, aSel);
void* returnIt(void* d, elt e)
{
return aSelImp(selObject, aSel, (id)d, e.id_t);
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self inject:initialArgObject byCalling:returnIt];
}
// OBJECT-COMPATIBLE MESSAGE NAMES
// ADDING;
- addObject: newObject
{
return [self addElement:newObject];
}
- addObjectIfAbsent: newObject
{
return [self addElementIfAbsent:newObject];
}
// REMOVING AND REPLACING;
- removeObject: oldObject
{
return [self removeElement:oldObject].id_t;
}
- removeAllOccurrencesOfObject: oldObject
{
return (id)[self removeAllOccurrencesOfObject:oldObject];
}
- replaceObject: oldObject with: newObject
{
return [self replaceElement:oldObject with:newObject].id_t;
}
- replaceAllOccurrencesOfObject: oldObject with: newObject
{
return [self replaceAllOccurrencesOfElement:oldObject with:newObject].id_t;
}
// TESTING;
- (BOOL) includesObject: anObject
{
return [self includesElement:anObject];
}
// ENUMERATING
- withObjectsCall: (void(*)(id))aFunc
{
void doIt(elt e)
{
aFunc(e.id_t);
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self withElementsCall:doIt];
}
- withObjectsCall: (void(*)(id))aFunc whileTrue:(BOOL *)flag
{
void doIt(elt e)
{
aFunc(e.id_t);
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self withElementsCall:doIt whileTrue:flag];
}
- withObjectsPerform: (SEL)aSel in: selObject
{
id (*aSelImp)(id,SEL,id) = (id(*)(id,SEL,id))
objc_msg_lookup(selObject, aSel);
void doIt(elt e)
{
aSelImp(selObject, aSel, e.id_t);
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
[self withElementsCall:doIt];
return self;
}
- withObjectsPerform: (SEL)aSel in: selObject with: argObject
{
id (*aSelImp)(id,SEL,id,id) = (id(*)(id,SEL,id,id))
objc_msg_lookup(selObject, aSel);
void doIt(elt e)
{
aSelImp(selObject, aSel, e.id_t, argObject);
}
if (OBJECTS_REQUIRED_WARNING())
return nil;
[self withElementsCall:doIt];
return self;
}
// NON-COPYING ENUMERATORS;
- detectObjectByCalling: (BOOL(*)(id))aFunc
{
if (OBJECTS_REQUIRED_WARNING())
return nil;
return [self detectElementByCalling:(BOOL(*)(elt))aFunc].id_t;
}
/* This printing stuff will change when we get Stream objects */
+ printElement: (elt)anElement description: (const char *)type
{
switch (*type)
{
case _C_CHARPTR:
case _C_ATOM:
printf("\"%s\"", anElement.char_ptr_t);
break;
case _C_ID:
case _C_CLASS:
printf("%s:0x%x", [anElement.id_t name], anElement.unsigned_int_t);
break;
case _C_PTR:
printf("0x%x", anElement.unsigned_int_t);
break;
case _C_SEL:
printf("%s", sel_get_name(anElement.SEL_t));
break;
case _C_INT:
printf("%d", anElement.int_t);
break;
case _C_UINT:
case _C_LNG:
case _C_ULNG:
printf("%d", anElement.unsigned_int_t);
break;
case _C_FLT:
printf("%f", anElement.float_t);
break;
default :
printf("unknown?");
}
return self;
}
- printElement: (elt)anElement
{
[[self class] printElement:anElement description:_description];
return self;
}
- printForDebugger
{
void doIt(elt e)
{
[self printElement:e];
printf(" ");
}
[self withElementsCall:doIt];
printf(" :%s\n", [self name]);
return self;
}
- oldprintForDebugger
{
void *s = 0;
elt e;
while ([self getNextElement:&e withEnumState:&s])
[self printElement:e];
printf(" :%s\n", [self name]);
return self;
}
// WARNING;
/* We should have a more general warning mechanism. */
static classWarn = YES; /* print warnings or not */
- warning:(const char *)aString,...
{
#define FMT "warning: %s (%s)\n %s\n"
char fmt[(strlen(FMT)+strlen(object_get_class_name(self))
+((aString!=0)?strlen(aString):0)+8)];
va_list ap;
if (classWarn)
{
sprintf(fmt, FMT, object_get_class_name(self),
object_is_instance(self)?"instance":"class",
(aString!=0)?aString:"");
va_start(ap, aString);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
return self;
#undef FMT
}
@end
@implementation Collection (ErrorReporting)
// ERROR REPORTING;
- errorElementNotFound: (elt)anElement inMethod: (SEL)aSel
{
[self warning:"in %s, couldn't find element 0x%x",
sel_get_name(aSel), anElement.unsigned_int_t];
return self;
}
- errorObjectsRequiredInMethod: (SEL)aSel
{
[self warning:"in %s, requires contents to be objects",
sel_get_name(aSel)];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.