diff --git a/ChangeLog b/ChangeLog index bdb264e93..db02aa385 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2016-02-22 Niels Grewe + * Headers/Foundation/NSObjCRuntime.h: Add macros for backwards- + compatible generics annotations. Also define instancetype if necessary. + * Headers/Foundation/NSArray.h + * Headers/Foundation/NSCache.h + * Headers/Foundation/NSDictionary.h + * Headers/Foundation/NSEnumerator.h + * Headers/Foundation/NSSet.h: Update interfaces for instancetype and + generics. + * Source/NSCache.m: Use NSMapTable instead of NSMutableDictionary. + The API contract for NSCache stipulates that keys are not copied, so + using a dictionary wasn't apropriate. + * Source/NSConnection.m + * Source/NSData.m: Small type safety improvements (mostly to keep the + compiler happy). + * Source/NSDictionary.m: Change id to id in a few places to + avoid compiler warnings. + * Tests/base/NSCache + * Tests/base/NSCache/TestInfo + * Tests/base/NSCache/basic.m + * Tests/base/NSCache/cache.m: + Test cases eviction from NSCache. Turns out we currently only evict + NSDiscardableContent, while the API documentation seems to suggest that cost + and count based eviction without NSDiscardableContent is also possible. + 2016-02-18 Richard Frith-Macdonald * Source/Additions/GSMime.m: @@ -65,7 +90,7 @@ thread object. Instead, we add it to a map table, keyed under the current thread ID, and use that in GSCurrentThread() to find the correct NSThread object - if pthread_getspecific wont return it to us. + if pthread_getspecific wont return it to us. * Tests/base/NSThread/late_unregister.m: Test case for late unregistration. diff --git a/Headers/Foundation/NSArray.h b/Headers/Foundation/NSArray.h index f1cd01ede..c1a4fd409 100644 --- a/Headers/Foundation/NSArray.h +++ b/Headers/Foundation/NSArray.h @@ -3,24 +3,24 @@ Written by: Andrew Kachites McCallum Created: 1995 - + This file is part of the GNUstep Base Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser 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 Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. - */ + */ #ifndef __NSArray_h_GNUSTEP_BASE_INCLUDE #define __NSArray_h_GNUSTEP_BASE_INCLUDE @@ -57,43 +57,49 @@ enum typedef NSUInteger NSBinarySearchingOptions; #endif -@interface NSArray : NSObject +@interface GS_GENERIC_CLASS(NSArray, __covariant ElementT) : NSObject -+ (id) array; -+ (id) arrayWithArray: (NSArray*)array; -+ (id) arrayWithContentsOfFile: (NSString*)file; ++ (instancetype) array; ++ (instancetype) arrayWithArray: (GS_GENERIC_CLASS(NSArray, ElementT) *)array; ++ (instancetype) arrayWithContentsOfFile: (NSString*)file; #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST) -+ (id) arrayWithContentsOfURL: (NSURL*)aURL; ++ (instancetype) arrayWithContentsOfURL: (NSURL*)aURL; #endif -+ (id) arrayWithObject: (id)anObject; -+ (id) arrayWithObjects: (id)firstObject, ...; -+ (id) arrayWithObjects: (const id[])objects count: (NSUInteger)count; ++ (instancetype) arrayWithObject: (id)anObject; ++ (instancetype) arrayWithObjects: (id)firstObject, ...; ++ (instancetype) arrayWithObjects: (const id[])objects count: (NSUInteger)count; -- (NSArray*) arrayByAddingObject: (id)anObject; -- (NSArray*) arrayByAddingObjectsFromArray: (NSArray*)anotherArray; -- (BOOL) containsObject: anObject; +- (GS_GENERIC_CLASS(NSArray, ElementT) *) arrayByAddingObject: + (GS_GENERIC_TYPE(ElementT))anObject; +- (GS_GENERIC_CLASS(NSArray, ElementT) *) arrayByAddingObjectsFromArray: + (GS_GENERIC_CLASS(NSArray, ElementT)*)anotherArray; +- (BOOL) containsObject: (GS_GENERIC_TYPE(ElementT))anObject; /** * Returns the number of elements contained in the receiver. */ - (NSUInteger) count; -- (void) getObjects: (__unsafe_unretained id[])aBuffer; -- (void) getObjects: (__unsafe_unretained id[])aBuffer range: (NSRange)aRange; -- (NSUInteger) indexOfObject: (id)anObject; -- (NSUInteger) indexOfObject: (id)anObject inRange: (NSRange)aRange; -- (NSUInteger) indexOfObjectIdenticalTo: (id)anObject; -- (NSUInteger) indexOfObjectIdenticalTo: (id)anObject inRange: (NSRange)aRange; -- (id) init; -- (id) initWithArray: (NSArray*)array; +- (void) getObjects: (__unsafe_unretained GS_GENERIC_TYPE(ElementT)[])aBuffer; +- (void) getObjects: (__unsafe_unretained GS_GENERIC_TYPE(ElementT)[])aBuffer + range: (NSRange)aRange; +- (NSUInteger) indexOfObject: (GS_GENERIC_TYPE(ElementT))anObject; +- (NSUInteger) indexOfObject: (GS_GENERIC_TYPE(ElementT))anObject + inRange: (NSRange)aRange; +- (NSUInteger) indexOfObjectIdenticalTo: (GS_GENERIC_TYPE(ElementT))anObject; +- (NSUInteger) indexOfObjectIdenticalTo: (GS_GENERIC_TYPE(ElementT))anObject + inRange: (NSRange)aRange; +- (instancetype) init; +- (instancetype) initWithArray: (GS_GENERIC_CLASS(NSArray, ElementT)*)array; #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST) -- (id) initWithArray: (NSArray*)array copyItems: (BOOL)shouldCopy; +- (instancetype) initWithArray: (GS_GENERIC_CLASS(NSArray, ElementT)*)array + copyItems: (BOOL)shouldCopy; #endif -- (id) initWithContentsOfFile: (NSString*)file; +- (instancetype) initWithContentsOfFile: (NSString*)file; #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST) -- (id) initWithContentsOfURL: (NSURL*)aURL; +- (instancetype) initWithContentsOfURL: (NSURL*)aURL; #endif -- (id) initWithObjects: firstObject, ...; +- (instancetype) initWithObjects: (GS_GENERIC_TYPE(ElementT)) firstObject, ...; /** * This should initialize the array with count (may be zero) objects.
@@ -102,24 +108,25 @@ typedef NSUInteger NSBinarySearchingOptions; * and needs to be re-implemented in subclasses in order to have all * other initialisers work. */ -- (id) initWithObjects: (const id[])objects - count: (NSUInteger)count; -- (id) lastObject; +- (instancetype) initWithObjects: (const GS_GENERIC_TYPE(ElementT)[])objects + count: (NSUInteger)count; +- (GS_GENERIC_TYPE(ElementT)) lastObject; #if OS_API_VERSION(MAC_OS_X_VERSION_10_6, GS_API_LATEST) -- (id) firstObject; +- (GS_GENERIC_TYPE(ElementT)) firstObject; #endif /** * Returns the object at the specified index. * Raises an exception of the index is beyond the array. */ -- (id) objectAtIndex: (NSUInteger)index; +- (GS_GENERIC_TYPE(ElementT)) objectAtIndex: (NSUInteger)index; #if OS_API_VERSION(MAC_OS_X_VERSION_10_4, GS_API_LATEST) -- (NSArray *) objectsAtIndexes: (NSIndexSet *)indexes; +- (GS_GENERIC_CLASS(NSArray, ElementT) *) objectsAtIndexes: (NSIndexSet *)indexes; #endif -- (id) firstObjectCommonWithArray: (NSArray*)otherArray; +- (GS_GENERIC_TYPE(ElementT)) firstObjectCommonWithArray: + (GS_GENERIC_CLASS(NSArray, ElementT) *)otherArray; - (BOOL) isEqualToArray: (NSArray*)otherArray; #if OS_API_VERSION(GS_API_OPENSTEP, GS_API_MACOSX) @@ -132,19 +139,22 @@ typedef NSUInteger NSBinarySearchingOptions; #endif - (NSData*) sortedArrayHint; -- (NSArray*) sortedArrayUsingFunction: (NSComparisonResult (*)(id, id, void*))comparator - context: (void*)context; -- (NSArray*) sortedArrayUsingFunction: (NSComparisonResult (*)(id, id, void*))comparator +- (GS_GENERIC_CLASS(NSArray, ElementT)*) sortedArrayUsingFunction: + (NSComparisonResult (*)(id, id, void*))comparator + context: (void*)context; +- (GS_GENERIC_CLASS(NSArray, ElementT)*) sortedArrayUsingFunction: + (NSComparisonResult (*)(id, id, void*))comparator context: (void*)context - hint: (NSData*)hint; -- (NSArray*) sortedArrayUsingSelector: (SEL)comparator; -- (NSArray*) subarrayWithRange: (NSRange)aRange; + hint: (NSData*)hint; +- (GS_GENERIC_CLASS(NSArray, ElementT)*) sortedArrayUsingSelector: (SEL)comparator; +- (GS_GENERIC_CLASS(NSArray, ElementT)*) subarrayWithRange: (NSRange)aRange; - (NSString*) componentsJoinedByString: (NSString*)separator; -- (NSArray*) pathsMatchingExtensions: (NSArray*)extensions; +- (GS_GENERIC_CLASS(NSArray, NSString*)*) pathsMatchingExtensions: + (GS_GENERIC_CLASS(NSArray, NSString*)*)extensions; -- (NSEnumerator*) objectEnumerator; -- (NSEnumerator*) reverseObjectEnumerator; +- (GS_GENERIC_CLASS(NSEnumerator, ElementT)*) objectEnumerator; +- (GS_GENERIC_CLASS(NSEnumerator, ElementT)*) reverseObjectEnumerator; - (NSString*) description; - (NSString*) descriptionWithLocale: (id)locale; @@ -154,14 +164,14 @@ typedef NSUInteger NSBinarySearchingOptions; - (BOOL) writeToFile: (NSString*)path atomically: (BOOL)useAuxiliaryFile; #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST) - (BOOL) writeToURL: (NSURL*)url atomically: (BOOL)useAuxiliaryFile; -- (id) valueForKey: (NSString*)key; -- (void) setValue: (id)value forKey: (NSString*)key; +- (GS_GENERIC_TYPE(ElementT)) valueForKey: (NSString*)key; +- (void) setValue: (GS_GENERIC_TYPE(ElementT))value forKey: (NSString*)key; #endif #if OS_API_VERSION(MAC_OS_X_VERSION_10_6, GS_API_LATEST) -DEFINE_BLOCK_TYPE(GSEnumeratorBlock, void, id, NSUInteger, BOOL*); -DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, id, NSUInteger, BOOL*); +DEFINE_BLOCK_TYPE(GSEnumeratorBlock, void, GS_GENERIC_TYPE(ElementT), NSUInteger, BOOL*); +DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, GS_GENERIC_TYPE(ElementT), NSUInteger, BOOL*); /** * Enumerate over the collection using the given block. The first argument is * the object and the second is the index in the array. The final argument is @@ -180,7 +190,7 @@ DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, id, NSUInteger, BOOL*); * specifies that it is thread-safe. The NSEnumerationReverse bit specifies * that it should be enumerated in reverse order. */ -- (void) enumerateObjectsWithOptions: (NSEnumerationOptions)opts +- (void) enumerateObjectsWithOptions: (NSEnumerationOptions)opts usingBlock: (GSEnumeratorBlock)aBlock; /** * Enumerate over the specified indexes in the collection using the given @@ -204,7 +214,7 @@ DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, id, NSUInteger, BOOL*); * specifies that it is thread-safe. The NSEnumerationReverse bit specifies * that it should be enumerated in reverse order. */ -- (NSIndexSet *) indexesOfObjectsWithOptions: (NSEnumerationOptions)opts +- (NSIndexSet *) indexesOfObjectsWithOptions: (NSEnumerationOptions)opts passingTest: (GSPredicateBlock)predicate; /** @@ -233,7 +243,7 @@ DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, id, NSUInteger, BOOL*); * specifies that it is thread-safe. The NSEnumerationReverse bit specifies * that it should be enumerated in reverse order. */ -- (NSUInteger) indexOfObjectWithOptions: (NSEnumerationOptions)opts +- (NSUInteger) indexOfObjectWithOptions: (NSEnumerationOptions)opts passingTest: (GSPredicateBlock)predicate; /** @@ -257,7 +267,8 @@ DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, id, NSUInteger, BOOL*); /** Returns a sorted array using the comparator to determine the * order of objects. */ -- (NSArray *) sortedArrayUsingComparator: (NSComparator)comparator; +- (GS_GENERIC_CLASS(NSArray, ElementT) *) sortedArrayUsingComparator: + (NSComparator)comparator; /** Returns a sorted array using the block to determine the order of objects. * @@ -265,8 +276,9 @@ DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, id, NSUInteger, BOOL*); * specifies that it is thread-safe. The NSSortStable bit specifies that * it should keep equal objects in the same order. */ -- (NSArray *) sortedArrayWithOptions: (NSSortOptions)options - usingComparator: (NSComparator)comparator; +- (GS_GENERIC_CLASS(NSArray, ElementT) *) + sortedArrayWithOptions: (NSSortOptions)options + usingComparator: (NSComparator)comparator; /** * Performs a binary search of the array within the specified range for the @@ -283,20 +295,20 @@ DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, id, NSUInteger, BOOL*); * Accessor for subscripting. This is called by the compiler when you write * code like anArray[12]. It should not be called directly. */ -- (id) objectAtIndexedSubscript: (size_t)anIndex; +- (GS_GENERIC_TYPE(ElementT)) objectAtIndexedSubscript: (size_t)anIndex; @end -@interface NSMutableArray : NSArray +@interface GS_GENERIC_CLASS(NSMutableArray, ElementT) : NSArray -+ (id) arrayWithCapacity: (NSUInteger)numItems; ++ (instancetype) arrayWithCapacity: (NSUInteger)numItems; /** * Adds anObject at the end of the array, thus increasing the size of * the array. The object is retained upon addition. */ -- (void) addObject: (id)anObject; -- (void) addObjectsFromArray: (NSArray*)otherArray; +- (void) addObject: (GS_GENERIC_TYPE(ElementT))anObject; +- (void) addObjectsFromArray: (GS_GENERIC_CLASS(NSArray, ElementT)*)otherArray; #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST) - (void) exchangeObjectAtIndex: (NSUInteger)i1 withObjectAtIndex: (NSUInteger)i2; @@ -309,7 +321,7 @@ DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, id, NSUInteger, BOOL*); * and needs to be re-implemented in subclasses in order to have all * other initialisers work. */ -- (id) initWithCapacity: (NSUInteger)numItems; +- (instancetype) initWithCapacity: (NSUInteger)numItems; /** * Inserts an object into the receiver at the specified location.
@@ -317,9 +329,11 @@ DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, id, NSUInteger, BOOL*); * The size of the array increases by one.
* The object is retained by the array. */ -- (void) insertObject: (id)anObject atIndex: (NSUInteger)index; +- (void) insertObject: (GS_GENERIC_TYPE(ElementT))anObject + atIndex: (NSUInteger)index; #if OS_API_VERSION(MAC_OS_X_VERSION_10_4, GS_API_LATEST) -- (void) insertObjects: (NSArray *)objects atIndexes: (NSIndexSet *)indexes; +- (void) insertObjects: (GS_GENERIC_CLASS(NSArray, ElementT) *)objects + atIndexes: (NSIndexSet *)indexes; #endif /** @@ -337,35 +351,39 @@ DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, id, NSUInteger, BOOL*); * The object is retained by the array. */ - (void) replaceObjectAtIndex: (NSUInteger)index - withObject: (id)anObject; + withObject: (GS_GENERIC_TYPE(ElementT))anObject; #if OS_API_VERSION(MAC_OS_X_VERSION_10_4, GS_API_LATEST) - (void) replaceObjectsAtIndexes: (NSIndexSet *)indexes - withObjects: (NSArray *)objects; + withObjects: (GS_GENERIC_CLASS(NSArray, ElementT)*)objects; #endif - (void) replaceObjectsInRange: (NSRange)aRange - withObjectsFromArray: (NSArray*)anArray; + withObjectsFromArray: (GS_GENERIC_CLASS(NSArray, ElementT)*)anArray; - (void) replaceObjectsInRange: (NSRange)aRange - withObjectsFromArray: (NSArray*)anArray - range: (NSRange)anotherRange; + withObjectsFromArray: (GS_GENERIC_CLASS(NSArray, ElementT)*)anArray + range: (NSRange)anotherRange; -- (void) setArray: (NSArray *)otherArray; +- (void) setArray: (GS_GENERIC_CLASS(NSArray, ElementT) *)otherArray; - (void) removeAllObjects; - (void) removeLastObject; -- (void) removeObject: (id)anObject; -- (void) removeObject: (id)anObject inRange: (NSRange)aRange; -- (void) removeObjectIdenticalTo: (id)anObject; -- (void) removeObjectIdenticalTo: (id)anObject inRange: (NSRange)aRange; -- (void) removeObjectsInArray: (NSArray*)otherArray; +- (void) removeObject: (GS_GENERIC_TYPE(ElementT))anObject; +- (void) removeObject: (GS_GENERIC_TYPE(ElementT))anObject + inRange: (NSRange)aRange; +- (void) removeObjectIdenticalTo: (GS_GENERIC_TYPE(ElementT))anObject; +- (void) removeObjectIdenticalTo: (GS_GENERIC_TYPE(ElementT))anObject + inRange: (NSRange)aRange; +- (void) removeObjectsInArray: (GS_GENERIC_CLASS(NSArray, ElementT)*)otherArray; - (void) removeObjectsInRange: (NSRange)aRange; -- (void) removeObjectsFromIndices: (NSUInteger*)indices +- (void) removeObjectsFromIndices: (NSUInteger*)indices numIndices: (NSUInteger)count; -- (void) sortUsingFunction: (NSComparisonResult (*)(id,id,void*))compare - context: (void*)context; +- (void) sortUsingFunction: + (NSComparisonResult (*)(GS_GENERIC_TYPE(ElementT), + GS_GENERIC_TYPE(ElementT),void*))compare + context: (void*)context; - (void) sortUsingSelector: (SEL)comparator; @@ -376,7 +394,7 @@ DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, id, NSUInteger, BOOL*); - (void) sortUsingComparator: (NSComparator)comparator; /** - * Sorts the array using the specified comparator block and options. + * Sorts the array using the specified comparator block and options. */ - (void) sortWithOptions: (NSSortOptions)options usingComparator: (NSComparator)comparator; @@ -384,7 +402,8 @@ DEFINE_BLOCK_TYPE(GSPredicateBlock, BOOL, id, NSUInteger, BOOL*); /** * Set method called by the compiler with array subscripting. */ -- (void) setObject: (id)anObject atIndexedSubscript: (size_t)anIndex; +- (void) setObject: (GS_GENERIC_TYPE(ElementT))anObject +atIndexedSubscript: (size_t)anIndex; @end #if defined(__cplusplus) diff --git a/Headers/Foundation/NSCache.h b/Headers/Foundation/NSCache.h index b4d299a55..5d3e9ef25 100644 --- a/Headers/Foundation/NSCache.h +++ b/Headers/Foundation/NSCache.h @@ -3,24 +3,24 @@ Written by: David Chisnall Created: 2009 - + This file is part of the GNUstep Base Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser 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 Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. - */ + */ #ifndef __NSCache_h_GNUSTEP_BASE_INCLUDE #define __NSCache_h_GNUSTEP_BASE_INCLUDE @@ -35,10 +35,10 @@ extern "C" { #endif @class NSString; -@class NSMutableDictionary; -@class NSMutableArray; +@class NSMapTable; +@class GS_GENERIC_CLASS(NSMutableArray, ElementT); -@interface NSCache : NSObject +@interface GS_GENERIC_CLASS(NSCache, KeyT, ValT) : NSObject { #if GS_EXPOSE(NSCache) @private @@ -55,9 +55,9 @@ extern "C" { /** Name of this cache. */ NSString *_name; /** The mapping from names to objects in this cache. */ - NSMutableDictionary *_objects; + NSMapTable *_objects; /** LRU ordering of all potentially-evictable objects in this cache. */ - NSMutableArray *_accesses; + GS_GENERIC_CLASS(NSMutableArray, ValT) *_accesses; /** Total number of accesses to objects */ int64_t _totalAccesses; #endif @@ -71,11 +71,16 @@ extern "C" { @private id _internal GS_UNUSED_IVAR; #endif } -/** +/** * Returns the maximum number of objects that are supported by this cache. */ - (NSUInteger) countLimit; +/** + * Returns the total cost of all objects held in the cache. + */ +- (NSUInteger) totalCostLimit; + /** * Returns the cache's delegate. */ @@ -96,7 +101,8 @@ extern "C" { /** * Returns an object associated with the specified key in this cache. */ -- (id) objectForKey: (id)key; +- (GS_GENERIC_TYPE(ValT)) objectForKey: + (GS_GENERIC_TYPE(KeyT))key; /** * Removes all objects from this cache. @@ -106,7 +112,7 @@ extern "C" { /** * Removes the object associated with the given key. */ -- (void) removeObjectForKey: (id)key; +- (void) removeObjectForKey: (GS_GENERIC_TYPE(KeyT))key; /** * Sets the maximum number of objects permitted in this cache. This limit is @@ -137,12 +143,15 @@ extern "C" { * total cost below the value set with -setTotalCostLimit: by discarding the * contents of objects which implement the NSDiscardableContent protocol. */ -- (void) setObject: (id)obj forKey: (id)key cost: (NSUInteger)num; +- (void) setObject: (GS_GENERIC_TYPE(ValT))obj + forKey: (GS_GENERIC_TYPE(KeyT))key + cost: (NSUInteger)num; /** * Adds an object to the cache without associating a cost with it. */ -- (void) setObject: (id)obj forKey: (id)key; +- (void) setObject: (GS_GENERIC_TYPE(ValT))obj + forKey: (GS_GENERIC_TYPE(KeyT))key; /** * Sets the maximum total cost for objects stored in this cache. This limit is diff --git a/Headers/Foundation/NSDictionary.h b/Headers/Foundation/NSDictionary.h index a0147d6c9..262b71403 100644 --- a/Headers/Foundation/NSDictionary.h +++ b/Headers/Foundation/NSDictionary.h @@ -33,25 +33,34 @@ extern "C" { #endif -@class NSArray, NSSet, NSString, NSURL; +@class GS_GENERIC_CLASS(NSArray, ElementT); +@class GS_GENERIC_CLASS(NSSet, ElementT); +@class NSString, NSURL; -@interface NSDictionary : NSObject -+ (id) dictionary; -+ (id) dictionaryWithContentsOfFile: (NSString*)path; +@interface GS_GENERIC_CLASS(NSDictionary, + __covariant KeyT:id, __covariant ValT) + : NSObject ++ (instancetype) dictionary; ++ (instancetype) dictionaryWithContentsOfFile: (NSString*)path; #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST) -+ (id) dictionaryWithContentsOfURL: (NSURL*)aURL; ++ (instancetype) dictionaryWithContentsOfURL: (NSURL*)aURL; #endif -+ (id) dictionaryWithDictionary: (NSDictionary*)otherDictionary; -+ (id) dictionaryWithObject: (id)object forKey: (id)key; -+ (id) dictionaryWithObjects: (NSArray*)objects forKeys: (NSArray*)keys; -+ (id) dictionaryWithObjects: (const id[])objects - forKeys: (const id [])keys - count: (NSUInteger)count; -+ (id) dictionaryWithObjectsAndKeys: (id)firstObject, ...; ++ (instancetype) dictionaryWithDictionary: (NSDictionary*)otherDictionary; ++ (instancetype) dictionaryWithObject: (GS_GENERIC_TYPE(ValT))object + forKey: + (GS_GENERIC_TYPE(KeyT))key; ++ (instancetype) dictionaryWithObjects: (GS_GENERIC_CLASS(NSArray,ValT)*)objects + forKeys: (GS_GENERIC_CLASS(NSArray,KeyT)*)keys; ++ (instancetype) dictionaryWithObjects: (const GS_GENERIC_TYPE(ValT)[])objects + forKeys: + (const GS_GENERIC_TYPE_F(KeyT,id)[])keys + count: (NSUInteger)count; ++ (instancetype) dictionaryWithObjectsAndKeys: (id)firstObject, ...; -- (NSArray*) allKeys; -- (NSArray*) allKeysForObject: (id)anObject; -- (NSArray*) allValues; +- (GS_GENERIC_CLASS(NSArray,KeyT)*) allKeys; +- (GS_GENERIC_CLASS(NSArray,KeyT)*) allKeysForObject: + (GS_GENERIC_TYPE(ValT))anObject; +- (GS_GENERIC_CLASS(NSArray,ValT)*) allValues; - (NSUInteger) count; // Primitive - (NSString*) description; - (NSString*) descriptionInStringsFileFormat; @@ -60,47 +69,58 @@ extern "C" { indent: (NSUInteger)level; #if OS_API_VERSION(MAC_OS_X_VERSION_10_6, GS_API_LATEST) -DEFINE_BLOCK_TYPE(GSKeysAndObjectsEnumeratorBlock, void, id, id, BOOL*); +DEFINE_BLOCK_TYPE(GSKeysAndObjectsEnumeratorBlock, void, + GS_GENERIC_TYPE_F(KeyT,id), GS_GENERIC_TYPE(ValT), BOOL*); - (void) enumerateKeysAndObjectsUsingBlock: (GSKeysAndObjectsEnumeratorBlock)aBlock; - (void) enumerateKeysAndObjectsWithOptions: (NSEnumerationOptions)opts usingBlock: (GSKeysAndObjectsEnumeratorBlock)aBlock; #endif -- (void) getObjects: (__unsafe_unretained id[])objects - andKeys: (__unsafe_unretained id[])keys; -- (id) init; -- (id) initWithContentsOfFile: (NSString*)path; +- (void) getObjects: (__unsafe_unretained GS_GENERIC_TYPE(ValT)[])objects + andKeys: + (__unsafe_unretained GS_GENERIC_TYPE_F(KeyT,id)[])keys; +- (instancetype) init; +- (instancetype) initWithContentsOfFile: (NSString*)path; #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST) -- (id) initWithContentsOfURL: (NSURL*)aURL; +- (instancetype) initWithContentsOfURL: (NSURL*)aURL; #endif -- (id) initWithDictionary: (NSDictionary*)otherDictionary; -- (id) initWithDictionary: (NSDictionary*)other copyItems: (BOOL)shouldCopy; -- (id) initWithObjects: (NSArray*)objects forKeys: (NSArray*)keys; -- (id) initWithObjectsAndKeys: (id)firstObject, ...; -- (id) initWithObjects: (const id[])objects - forKeys: (const id [])keys +- (instancetype) initWithDictionary: + (GS_GENERIC_CLASS(NSDictionary,KeyT, ValT)*)otherDictionary; +- (id) initWithDictionary: (GS_GENERIC_CLASS(NSDictionary,KeyT, ValT)*)other + copyItems: (BOOL)shouldCopy; +- (id) initWithObjects: (GS_GENERIC_CLASS(NSArray,KeyT)*)objects + forKeys: (GS_GENERIC_CLASS(NSArray,ValT)*)keys; +- (id) initWithObjectsAndKeys: (GS_GENERIC_TYPE(ValT))firstObject, ...; +- (id) initWithObjects: (const GS_GENERIC_TYPE(ValT)[])objects + forKeys: (const GS_GENERIC_TYPE_F(KeyT,id)[])keys count: (NSUInteger)count; // Primitive -- (BOOL) isEqualToDictionary: (NSDictionary*)other; +- (BOOL) isEqualToDictionary: (GS_GENERIC_CLASS(NSDictionary,KeyT, ValT)*)other; -- (NSEnumerator*) keyEnumerator; // Primitive +- (GS_GENERIC_CLASS(NSEnumerator,KeyT)*) keyEnumerator; // Primitive #if OS_API_VERSION(MAC_OS_X_VERSION_10_6, GS_API_LATEST) -DEFINE_BLOCK_TYPE(GSKeysAndObjectsPredicateBlock, BOOL, id, id, BOOL*); -- (NSSet*) keysOfEntriesPassingTest: (GSKeysAndObjectsPredicateBlock)aPredicate; -- (NSSet*) keysOfEntriesWithOptions: (NSEnumerationOptions)opts +DEFINE_BLOCK_TYPE(GSKeysAndObjectsPredicateBlock, BOOL, + GS_GENERIC_TYPE_F(KeyT,id), GS_GENERIC_TYPE(ValT), BOOL*); +- (GS_GENERIC_CLASS(NSSet,KeyT)*) keysOfEntriesPassingTest: + (GSKeysAndObjectsPredicateBlock)aPredicate; +- (GS_GENERIC_CLASS(NSSet,KeyT)*) keysOfEntriesWithOptions: + (NSEnumerationOptions)opts passingTest: (GSKeysAndObjectsPredicateBlock)aPredicate; #endif -- (NSArray*) keysSortedByValueUsingSelector: (SEL)comp; -- (NSEnumerator*) objectEnumerator; // Primitive -- (id) objectForKey: (id)aKey; // Primitive -- (NSArray*) objectsForKeys: (NSArray*)keys notFoundMarker: (id)marker; +- (GS_GENERIC_CLASS(NSArray,ValT)*) keysSortedByValueUsingSelector: (SEL)comp; +- (GS_GENERIC_CLASS(NSEnumerator,ValT)*) objectEnumerator; // Primitive +- (GS_GENERIC_TYPE(ValT)) objectForKey: + (GS_GENERIC_TYPE(KeyT))aKey; // Primitive +- (GS_GENERIC_CLASS(NSArray,ValT)*) objectsForKeys: + (GS_GENERIC_CLASS(NSArray,KeyT)*)keys + notFoundMarker: (GS_GENERIC_TYPE(ValT))marker; #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST) -- (id) valueForKey: (NSString*)key; +- (GS_GENERIC_TYPE(ValT)) valueForKey: (NSString*)key; #endif - (BOOL) writeToFile: (NSString*)path atomically: (BOOL)useAuxiliaryFile; @@ -111,29 +131,39 @@ DEFINE_BLOCK_TYPE(GSKeysAndObjectsPredicateBlock, BOOL, id, id, BOOL*); /** * Method called by array subscripting. */ -- (id) objectForKeyedSubscript: (id)aKey; +- (GS_GENERIC_TYPE(ValT)) objectForKeyedSubscript: + (GS_GENERIC_TYPE(KeyT))aKey; @end -@interface NSMutableDictionary: NSDictionary +@interface GS_GENERIC_CLASS(NSMutableDictionary, KeyT:id, ValT) : + GS_GENERIC_CLASS(NSDictionary, KeyT, ValT) -+ (id) dictionaryWithCapacity: (NSUInteger)numItems; ++ (instancetype) dictionaryWithCapacity: (NSUInteger)numItems; -- (void) addEntriesFromDictionary: (NSDictionary*)otherDictionary; -- (id) initWithCapacity: (NSUInteger)numItems; // Primitive +- (void) addEntriesFromDictionary: + (GS_GENERIC_CLASS(NSDictionary, KeyT, ValT)*)otherDictionary; +- (instancetype) initWithCapacity: (NSUInteger)numItems; // Primitive - (void) removeAllObjects; -- (void) removeObjectForKey: (id)aKey; // Primitive -- (void) removeObjectsForKeys: (NSArray*)keyArray; -- (void) setObject: (id)anObject forKey: (id)aKey; // Primitive -- (void) setDictionary: (NSDictionary*)otherDictionary; +/** + * Removes the object with the specified key from the receiver. This method + * is primitive. + */ +- (void) removeObjectForKey: (GS_GENERIC_TYPE(KeyT))aKey; +- (void) removeObjectsForKeys: (GS_GENERIC_CLASS(NSArray, KeyT) *)keyArray; +- (void) setObject: (GS_GENERIC_TYPE(ValT))anObject + forKey: (GS_GENERIC_TYPE(KeyT))aKey; // Primitive +- (void) setDictionary: + (GS_GENERIC_CLASS(NSDictionary, KeyT, ValT)*)otherDictionary; #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST) -- (void) setValue: (id)value forKey: (NSString*)key; -- (void) takeStoredValue: (id)value forKey: (NSString*)key; -- (void) takeValue: (id)value forKey: (NSString*)key; +- (void) setValue: (GS_GENERIC_TYPE(ValT))value forKey: (NSString*)key; +- (void) takeStoredValue: (GS_GENERIC_TYPE(ValT))value forKey: (NSString*)key; +- (void) takeValue: (GS_GENERIC_TYPE(ValT))value forKey: (NSString*)key; #endif /** * Method called by array subscripting. */ -- (void) setObject: (id)anObject forKeyedSubscript: (id)aKey; +- (void) setObject: (GS_GENERIC_TYPE(ValT))anObject + forKeyedSubscript: (GS_GENERIC_TYPE(KeyT))aKey; @end diff --git a/Headers/Foundation/NSEnumerator.h b/Headers/Foundation/NSEnumerator.h index 91a8cf4f1..e5ad47587 100644 --- a/Headers/Foundation/NSEnumerator.h +++ b/Headers/Foundation/NSEnumerator.h @@ -1,4 +1,4 @@ -/* +/* NSEnumerator.h Copyright (C) 1998 Free Software Foundation, Inc. @@ -12,7 +12,7 @@ modify it under the terms of the GNU Lesser 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 @@ -30,11 +30,14 @@ #import + #if defined(__cplusplus) extern "C" { #endif -typedef struct +@class GS_GENERIC_CLASS(NSArray, ElementT); + +typedef struct { unsigned long state; __unsafe_unretained id *itemsPtr; @@ -43,14 +46,14 @@ typedef struct } NSFastEnumerationState; @protocol NSFastEnumeration -- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState *)state +- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState *)state objects: (__unsafe_unretained id[])stackbuf count: (NSUInteger)len; @end -@interface NSEnumerator : NSObject -- (NSArray *) allObjects; -- (id) nextObject; +@interface GS_GENERIC_CLASS(NSEnumerator, IterT) : NSObject +- (GS_GENERIC_CLASS(NSArray, IterT) *) allObjects; +- (GS_GENERIC_TYPE(IterT)) nextObject; @end #if defined(__cplusplus) diff --git a/Headers/Foundation/NSObjCRuntime.h b/Headers/Foundation/NSObjCRuntime.h index 60f23031c..776a8cfb3 100644 --- a/Headers/Foundation/NSObjCRuntime.h +++ b/Headers/Foundation/NSObjCRuntime.h @@ -48,7 +48,7 @@ #if defined(__hppa__) && defined(__hpux__) && !defined(PRIuPTR) #define PRIuPTR "lu" #endif - + /* IRIX kludge. */ #if defined(__sgi) /* IRIX 6.5 provides all definitions, but only for C99 @@ -70,7 +70,7 @@ are uintptr_t, which is always unsigned long. */ #define PRIuPTR "lu" #endif - + /* Solaris < 10 kludge. */ #if defined(__sun__) && defined(__svr4__) && !defined(PRIuPTR) #if defined(__arch64__) || defined (__x86_64__) @@ -157,11 +157,30 @@ extern "C" { #if __has_feature(nullability) # define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin") # define NS_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end") -#else +#else # define NS_ASSUME_NONNULL_BEGIN # define NS_ASSUME_NONNULL_END #endif +/* + * Backwards compatibility macro for instance type. + */ +#if !__has_feature(objc_instancetype) +# define instancetype id +#endif + +/* + * Backwards compatibility macros for Objective-C lightweight generics. + */ +#if __has_feature(objc_generics) +# define GS_GENERIC_CLASS(clz, ...) clz<__VA_ARGS__> +# define GS_GENERIC_TYPE_F(typeRef, fallback) typeRef +#else +# define GS_GENERIC_CLASS(clz, ...) clz +# define GS_GENERIC_TYPE_F(typeRef, fallback) fallback +#endif +#define GS_GENERIC_TYPE(typeRef) GS_GENERIC_TYPE_F(typeRef, id) + /** Bitfield used to specify options to control enumeration over collections. */ typedef NS_OPTIONS(NSUInteger, NSEnumerationOptions) diff --git a/Headers/Foundation/NSSet.h b/Headers/Foundation/NSSet.h index 12844aabc..ba302295f 100644 --- a/Headers/Foundation/NSSet.h +++ b/Headers/Foundation/NSSet.h @@ -3,19 +3,19 @@ Written by: Andrew Kachites McCallum Created: Sep 1995 - + This file is part of the GNUstep Base Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser 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 Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, @@ -24,7 +24,7 @@ AutogsdocSource: NSSet.m AutogsdocSource: NSCountedSet.m - */ + */ #ifndef _NSSet_h_GNUSTEP_BASE_INCLUDE #define _NSSet_h_GNUSTEP_BASE_INCLUDE @@ -38,38 +38,45 @@ extern "C" { #endif -@class NSArray, NSString, NSEnumerator, NSDictionary; +@class GS_GENERIC_CLASS(NSArray, ElementT); +@class GS_GENERIC_CLASS(NSEnumerator, ElementT); +@class GS_GENERIC_CLASS(NSDictionary, KeyT:id, ValT); +@class NSString; -@interface NSSet : NSObject +@interface GS_GENERIC_CLASS(NSSet, __covariant ElementT) : NSObject -+ (id) set; -+ (id) setWithArray: (NSArray*)objects; -+ (id) setWithObject: (id)anObject; -+ (id) setWithObjects: (id)firstObject, ...; ++ (instancetype) set; ++ (instancetype) setWithArray: (GS_GENERIC_CLASS(NSArray, ElementT)*)objects; ++ (instancetype) setWithObject: (GS_GENERIC_TYPE(ElementT))anObject; ++ (instancetype) setWithObjects: (GS_GENERIC_TYPE(ElementT))firstObject, ...; #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST) -+ (id) setWithObjects: (const id[])objects - count: (NSUInteger)count; ++ (instancetype) setWithObjects: (const GS_GENERIC_TYPE(ElementT)[])objects + count: (NSUInteger)count; #endif -+ (id) setWithSet: (NSSet*)aSet; ++ (instancetype) setWithSet: (GS_GENERIC_CLASS(NSSet, ElementT)*)aSet; -- (NSArray*) allObjects; -- (id) anyObject; -- (BOOL) containsObject: (id)anObject; +- (GS_GENERIC_CLASS(NSArray, ElementT)*) allObjects; +- (GS_GENERIC_TYPE(ElementT)) anyObject; +- (BOOL) containsObject: (GS_GENERIC_TYPE(ElementT))anObject; - (NSUInteger) count; - (NSString*) description; - (NSString*) descriptionWithLocale: (id)locale; -- (id) init; -- (id) initWithArray: (NSArray*)other; -- (id) initWithObjects: (id)firstObject, ...; -- (id) initWithObjects: (const id[])objects - count: (NSUInteger)count; -- (id) initWithSet: (NSSet*)other; -- (id) initWithSet: (NSSet*)other copyItems: (BOOL)flag; +- (instancetype) init; +- (instancetype) initWithArray: (GS_GENERIC_CLASS(NSArray, ElementT)*)other; +- (instancetype) initWithObjects: (GS_GENERIC_TYPE(ElementT))firstObject, ...; +- (instancetype) initWithObjects: (const GS_GENERIC_TYPE(ElementT)[])objects + count: (NSUInteger)count; +- (instancetype) initWithSet: (GS_GENERIC_CLASS(NSSet, ElementT)*)other; +- (instancetype) initWithSet: (GS_GENERIC_CLASS(NSSet, ElementT)*)other + copyItems: (BOOL)flag; -- (BOOL) intersectsSet: (NSSet*)otherSet; -- (BOOL) isEqualToSet: (NSSet*)other; -- (BOOL) isSubsetOfSet: (NSSet*)otherSet; +- (BOOL) intersectsSet: (GS_GENERIC_CLASS(NSSet, ElementT)*)otherSet; +- (BOOL) isEqualToSet: (GS_GENERIC_CLASS(NSSet, ElementT)*)other; +- (BOOL) isSubsetOfSet: (GS_GENERIC_CLASS(NSSet, ElementT)*)otherSet; - (void) makeObjectsPerform: (SEL)aSelector; - (void) makeObjectsPerform: (SEL)aSelector withObject: (id)argument; @@ -77,13 +84,13 @@ extern "C" { - (void) makeObjectsPerformSelector: (SEL)aSelector; - (void) makeObjectsPerformSelector: (SEL)aSelector withObject: (id)argument; #endif -- (id) member: (id)anObject; -- (NSEnumerator*) objectEnumerator; +- (GS_GENERIC_TYPE(ElementT)) member: (GS_GENERIC_TYPE(ElementT))anObject; +- (GS_GENERIC_CLASS(NSEnumerator, ElementT)*) objectEnumerator; #if OS_API_VERSION(MAC_OS_X_VERSION_10_6, GS_API_LATEST) -DEFINE_BLOCK_TYPE(GSSetEnumeratorBlock, void, id, BOOL*); -DEFINE_BLOCK_TYPE(GSSetFilterBlock, BOOL, id, BOOL*); +DEFINE_BLOCK_TYPE(GSSetEnumeratorBlock, void, GS_GENERIC_TYPE(ElementT), BOOL*); +DEFINE_BLOCK_TYPE(GSSetFilterBlock, BOOL, GS_GENERIC_TYPE(ElementT), BOOL*); /** * Enumerate over the collection using a given block. The first argument is @@ -106,40 +113,46 @@ DEFINE_BLOCK_TYPE(GSSetFilterBlock, BOOL, id, BOOL*); - (void) enumerateObjectsWithOptions: (NSEnumerationOptions)opts usingBlock: (GSSetEnumeratorBlock)aBlock; -- (NSSet *) objectsPassingTest: (GSSetFilterBlock)aBlock; - -- (NSSet *) objectsWithOptions: (NSEnumerationOptions)opts - passingTest: (GSSetFilterBlock)aBlock; +- (GS_GENERIC_CLASS(NSSet, ElementT) *) objectsPassingTest: + (GSSetFilterBlock)aBlock; +- (GS_GENERIC_CLASS(NSSet, ElementT) *) objectsWithOptions: + (NSEnumerationOptions)opts + passingTest: (GSSetFilterBlock)aBlock; #endif -#if OS_API_VERSION(MAC_OS_X_VERSION_10_5,GS_API_LATEST) -- (NSSet *) setByAddingObject: (id)anObject; -- (NSSet *) setByAddingObjectsFromSet: (NSSet *)other; -- (NSSet *) setByAddingObjectsFromArray: (NSArray *)other; +#if OS_API_VERSION(MAC_OS_X_VERSION_10_5,GS_API_LATEST) +- (GS_GENERIC_CLASS(NSSet, ElementT) *) setByAddingObject: + (GS_GENERIC_TYPE(ElementT))anObject; +- (GS_GENERIC_CLASS(NSSet, ElementT) *) setByAddingObjectsFromSet: + (GS_GENERIC_CLASS(NSSet, ElementT) *)other; +- (GS_GENERIC_CLASS(NSSet, ElementT) *) setByAddingObjectsFromArray: + (GS_GENERIC_CLASS(NSArray, ElementT) *)other; #endif @end -@interface NSMutableSet: NSSet +@interface GS_GENERIC_CLASS(NSMutableSet, ElementT): + GS_GENERIC_CLASS(NSSet, ElementT) -+ (id) setWithCapacity: (NSUInteger)numItems; ++ (instancetype) setWithCapacity: (NSUInteger)numItems; -- (void) addObject: (id)anObject; -- (void) addObjectsFromArray: (NSArray*)array; -- (id) initWithCapacity: (NSUInteger)numItems; -- (void) intersectSet: (NSSet*)other; -- (void) minusSet: (NSSet*)other; +- (void) addObject: (GS_GENERIC_TYPE(ElementT))anObject; +- (void) addObjectsFromArray: (GS_GENERIC_CLASS(NSArray, ElementT)*)array; +- (instancetype) initWithCapacity: (NSUInteger)numItems; +- (void) intersectSet: (GS_GENERIC_CLASS(NSSet, ElementT)*)other; +- (void) minusSet: (GS_GENERIC_CLASS(NSSet, ElementT)*)other; - (void) removeAllObjects; -- (void) removeObject: (id)anObject; +- (void) removeObject: (GS_GENERIC_TYPE(ElementT))anObject; #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST) -- (void) setSet: (NSSet*)other; +- (void) setSet: (GS_GENERIC_CLASS(NSSet, ElementT)*)other; #endif -- (void) unionSet: (NSSet*)other; +- (void) unionSet: (GS_GENERIC_CLASS(NSSet, ElementT)*)other; @end -@interface NSCountedSet : NSMutableSet +@interface GS_GENERIC_CLASS(NSCountedSet, ElementT) : + GS_GENERIC_CLASS(NSMutableSet, ElementT) -- (NSUInteger) countForObject: (id)anObject; +- (NSUInteger) countForObject: (GS_GENERIC_TYPE(ElementT))anObject; @end @@ -148,7 +161,7 @@ DEFINE_BLOCK_TYPE(GSSetFilterBlock, BOOL, id, BOOL*); /** * Utility methods for using a counted set to handle uniquing of objects. */ -@interface NSCountedSet (GNU_Uniquing) +@interface GS_GENERIC_CLASS(NSCountedSet, ElementT) (GNU_Uniquing) /** *

* This method removes from the set all objects whose count is @@ -170,7 +183,7 @@ DEFINE_BLOCK_TYPE(GSSetFilterBlock, BOOL, id, BOOL*); * is released, and the object in the set is retained and returned. * Otherwise, the supplied object is added to the set and returned. *

- *

+ *

* This method is useful for uniquing objects - the init method of * a class need simply end with - * @@ -178,7 +191,8 @@ DEFINE_BLOCK_TYPE(GSSetFilterBlock, BOOL, id, BOOL*); * *

*/ -- (id) unique: (id) NS_CONSUMED anObject NS_RETURNS_RETAINED; +- (GS_GENERIC_TYPE(ElementT)) unique: + (GS_GENERIC_TYPE(ElementT)) NS_CONSUMED anObject NS_RETURNS_RETAINED; @end /* @@ -190,7 +204,7 @@ DEFINE_BLOCK_TYPE(GSSetFilterBlock, BOOL, id, BOOL*); * if uniquing is turned off, GSUnique() simply returns its argument. * */ -void GSUniquing(BOOL flag); +void GSUniquing(BOOL flag); /* * GSUnique() returns an object that is equal to the one passed to it. diff --git a/Source/NSCache.m b/Source/NSCache.m index 9cb73e85d..9591e85a9 100644 --- a/Source/NSCache.m +++ b/Source/NSCache.m @@ -3,24 +3,24 @@ Written by: David Chisnall Created: 2009 - + This file is part of the GNUstep Base Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser 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 Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. - */ + */ #import "common.h" @@ -28,7 +28,7 @@ #import "Foundation/NSArray.h" #import "Foundation/NSCache.h" -#import "Foundation/NSDictionary.h" +#import "Foundation/NSMapTable.h" #import "Foundation/NSEnumerator.h" /** @@ -60,7 +60,7 @@ { return nil; } - _objects = [NSMutableDictionary new]; + ASSIGN(_objects,[NSMapTable strongToStrongObjectsMapTable]); _accesses = [NSMutableArray new]; return self; } diff --git a/Source/NSConnection.m b/Source/NSConnection.m index 2087a2340..e3269af9b 100644 --- a/Source/NSConnection.m +++ b/Source/NSConnection.m @@ -103,15 +103,15 @@ skip_argspec(const char *ptr) */ #define GSI_MAP_KTYPES GSUNION_PTR | GSUNION_OBJ | GSUNION_NSINT #define GSI_MAP_VTYPES GSUNION_PTR | GSUNION_OBJ -#define GSI_MAP_RETAIN_KEY(M, X) -#define GSI_MAP_RELEASE_KEY(M, X) -#define GSI_MAP_RETAIN_VAL(M, X) -#define GSI_MAP_RELEASE_VAL(M, X) +#define GSI_MAP_RETAIN_KEY(M, X) +#define GSI_MAP_RELEASE_KEY(M, X) +#define GSI_MAP_RETAIN_VAL(M, X) +#define GSI_MAP_RELEASE_VAL(M, X) #define GSI_MAP_HASH(M, X) ((X).nsu ^ ((X).nsu >> 3)) #define GSI_MAP_EQUAL(M, X,Y) ((X).ptr == (Y).ptr) #define GSI_MAP_NOCLEAN 1 #if GS_WITH_GC -// FIXME ... +// FIXME ... #include static GC_descr nodeDesc; // Type descriptor for map node. #define GSI_MAP_NODES(M, X) \ @@ -174,7 +174,7 @@ GSRunLoopForThread(NSThread *aThread) @interface NSConnection (GNUstepExtensions) - (void) finalize; -- (void) forwardInvocation: (NSInvocation *)inv +- (void) forwardInvocation: (NSInvocation *)inv forProxy: (NSDistantObject*)object; - (const char *) typeForSelector: (SEL)sel remoteTarget: (unsigned)target; @end @@ -765,7 +765,7 @@ static NSLock *cached_proxies_gate = nil; return AUTORELEASE(proxy); } -+ (id) serviceConnectionWithName: (NSString *)name ++ (id) serviceConnectionWithName: (NSString *)name rootObject: (id)root { return [self serviceConnectionWithName: name @@ -773,7 +773,7 @@ static NSLock *cached_proxies_gate = nil; usingNameServer: [NSPortNameServer systemDefaultPortNameServer]]; } -+ (id) serviceConnectionWithName: (NSString *)name ++ (id) serviceConnectionWithName: (NSString *)name rootObject: (id)root usingNameServer: (NSPortNameServer *)server { @@ -1421,31 +1421,34 @@ static NSLock *cached_proxies_gate = nil; */ - (NSArray*) localObjects { - NSMutableArray *c; + NSArray *a; /* Don't assert (IisValid); */ GS_M_LOCK(IrefGate); if (IlocalObjects != 0) { + GSIMapEnumerator_t enumerator; GSIMapNode node; enumerator = GSIMapEnumeratorForMap(IlocalObjects); node = GSIMapEnumeratorNextNode(&enumerator); - c = [NSMutableArray arrayWithCapacity: IlocalObjects->nodeCount]; + NSMutableArray *c = + [NSMutableArray arrayWithCapacity: IlocalObjects->nodeCount]; while (node != 0) { [c addObject: node->key.obj]; node = GSIMapEnumeratorNextNode(&enumerator); } + a = c; } else { - c = [NSArray array]; + a = [NSArray array]; } GSM_UNLOCK(IrefGate); - return c; + return a; } /** @@ -2105,7 +2108,7 @@ static NSLock *cached_proxies_gate = nil; format: @"connection waiting for request was shut down"]; } aRmc = [self _getReplyRmc: seq]; - + /* * Find out if the server is returning an exception instead * of the return values. @@ -2136,7 +2139,7 @@ static NSLock *cached_proxies_gate = nil; /* If there is a return value, decode it, and put it in datum. */ if (*tmptype != _C_VOID || (flags & _F_ONEWAY) == 0) - { + { switch (*tmptype) { case _C_ID: @@ -2586,7 +2589,7 @@ static NSLock *cached_proxies_gate = nil; */ object = [decoder decodeObject]; - /* Decode the selector, (which is the second argument to a method). */ + /* Decode the selector, (which is the second argument to a method). */ /* xxx @encode(SEL) produces "^v" in gcc 2.5.8. It should be ":" */ [decoder decodeValueOfObjCType: @encode(SEL) at: &selector]; @@ -2606,14 +2609,14 @@ static NSLock *cached_proxies_gate = nil; object, sel_getName(selector)]; } type = [sig methodType]; - + /* Make sure we successfully got the method type, and that its types match the ENCODED_TYPES. */ NSCParameterAssert (type); if (GSSelectorTypesMatch(encoded_types, type) == NO) { [NSException raise: NSInvalidArgumentException - format: @"NSConection types (%s / %s) missmatch for %s", + format: @"NSConection types (%s / %s) missmatch for %s", encoded_types, type, sel_getName(selector)]; } @@ -3394,7 +3397,7 @@ static NSLock *cached_proxies_gate = nil; sendPort:IsendPort components: nil]; [coder encodeValueOfObjCType: @encode(int) at: &sno]; - NSDebugMLLog(@"NSConnection", + NSDebugMLLog(@"NSConnection", @"Make out RMC %u on %@", sno, self); return coder; } @@ -3441,7 +3444,7 @@ static NSLock *cached_proxies_gate = nil; break; } - NSDebugMLLog(@"NSConnection", + NSDebugMLLog(@"NSConnection", @"Sending %@ on %@", stringFromMsgType(msgid), self); limit = [dateClass dateWithTimeIntervalSinceNow: IrequestTimeout]; @@ -4035,7 +4038,7 @@ static NSLock *cached_proxies_gate = nil; * We enumerate an array copy of the contents of the hash table * as we know we can do that safely outside the locked region. * The temporary array and the enumerator are autoreleased and - * will be deallocated with the threads autorelease pool. + * will be deallocated with the threads autorelease pool. */ while ((c = [enumerator nextObject]) != nil) { @@ -4044,4 +4047,3 @@ static NSLock *cached_proxies_gate = nil; } } @end - diff --git a/Source/NSData.m b/Source/NSData.m index 46efe24a9..0b088752e 100644 --- a/Source/NSData.m +++ b/Source/NSData.m @@ -64,7 +64,7 @@ * Since all the other subclasses are based on NSDataMalloc or * NSMutableDataMalloc, we can put most methods in here and not * bother with duplicating them in the other classes. - * + * */ #import "common.h" @@ -166,7 +166,7 @@ encodebase64(unsigned char **dstRef, NSUInteger lineLength; NSUInteger destLen; - lineLength = 0; + lineLength = 0; if (options & NSDataBase64Encoding64CharacterLineLength) lineLength = 64; else if (options & NSDataBase64Encoding76CharacterLineLength) @@ -243,28 +243,28 @@ readContentsOfFile(NSString* path, void** buf, off_t* len, NSZone* zone) const unichar *thePath = 0; #else const char *thePath = 0; -#endif +#endif FILE *theFile = 0; void *tmp = 0; int c; off_t fileLength; - + #if defined(__MINGW__) thePath = (const unichar*)[path fileSystemRepresentation]; #else thePath = [path fileSystemRepresentation]; -#endif +#endif if (thePath == 0) { NSWarnFLog(@"Open (%@) attempt failed - bad path", path); return NO; } - + #if defined(__MINGW__) theFile = _wfopen(thePath, L"rb"); #else theFile = fopen(thePath, "rb"); -#endif +#endif if (theFile == 0) /* We failed to open the file. */ { @@ -282,7 +282,7 @@ readContentsOfFile(NSString* path, void** buf, off_t* len, NSZone* zone) [NSError _last]); goto failure; } - + /* * Determine the length of the file (having seeked to the end of the * file) by calling ftello(). @@ -293,7 +293,7 @@ readContentsOfFile(NSString* path, void** buf, off_t* len, NSZone* zone) NSWarnFLog(@"Ftell on %@ failed - %@", path, [NSError _last]); goto failure; } - + /* * Rewind the file pointer to the beginning, preparing to read in * the file. @@ -310,7 +310,7 @@ readContentsOfFile(NSString* path, void** buf, off_t* len, NSZone* zone) if (fileLength == 0) { unsigned char buf[BUFSIZ]; - + /* * Special case ... a file of length zero may be a named pipe or some * file in the /proc filesystem, which will return us data if we read @@ -362,7 +362,7 @@ readContentsOfFile(NSString* path, void** buf, off_t* len, NSZone* zone) (intmax_t)fileLength, [NSError _last]); goto failure; } - + while (offset < fileLength && (c = fread(tmp + offset, 1, fileLength - offset, theFile)) != 0) { @@ -389,7 +389,7 @@ readContentsOfFile(NSString* path, void** buf, off_t* len, NSZone* zone) *len = fileLength; fclose(theFile); return YES; - + /* * Just in case the failure action needs to be changed. */ @@ -1736,7 +1736,7 @@ failure: { c = 0; // Delete the old file if possible - DeleteFileW(secondaryFile); + DeleteFileW(secondaryFile); } else { @@ -1814,15 +1814,15 @@ failure: useAuxiliaryFile = YES; } if ([path canBeConvertedToEncoding: [NSString defaultCStringEncoding]]) - { + { const char *local_c_path = [path cString]; if (local_c_path != 0 && strlen(local_c_path) < (BUFSIZ*2)) - { + { strncpy(theRealPath, local_c_path, sizeof(theRealPath) - 1); theRealPath[sizeof(theRealPath) - 1] = '\0'; error_BadPath = NO; - } + } } if (error_BadPath) { @@ -1918,13 +1918,11 @@ failure: if (useAuxiliaryFile) { NSFileManager *mgr = [NSFileManager defaultManager]; - NSMutableDictionary *att = nil; + NSDictionary *att = nil; if ([mgr fileExistsAtPath: path]) { - att = [[mgr fileAttributesAtPath: path - traverseLink: YES] mutableCopy]; - IF_NO_GC(AUTORELEASE(att)); + att = [mgr fileAttributesAtPath: path traverseLink: YES]; } c = rename(thePath, theRealPath); @@ -1937,18 +1935,20 @@ failure: if (att != nil) { + NSMutableDictionary *mAtt = [att mutableCopy]; + IF_NO_GC(AUTORELEASE(mAtt)); /* * We have created a new file - so we attempt to make it's * attributes match that of the original. */ - [att removeObjectForKey: NSFileSize]; - [att removeObjectForKey: NSFileModificationDate]; - [att removeObjectForKey: NSFileReferenceCount]; - [att removeObjectForKey: NSFileSystemNumber]; - [att removeObjectForKey: NSFileSystemFileNumber]; - [att removeObjectForKey: NSFileDeviceIdentifier]; - [att removeObjectForKey: NSFileType]; - if ([mgr changeFileAttributes: att atPath: path] == NO) + [mAtt removeObjectForKey: NSFileSize]; + [mAtt removeObjectForKey: NSFileModificationDate]; + [mAtt removeObjectForKey: NSFileReferenceCount]; + [mAtt removeObjectForKey: NSFileSystemNumber]; + [mAtt removeObjectForKey: NSFileSystemFileNumber]; + [mAtt removeObjectForKey: NSFileDeviceIdentifier]; + [mAtt removeObjectForKey: NSFileType]; + if ([mgr changeFileAttributes: mAtt atPath: path] == NO) { NSWarnMLog(@"Unable to correctly set all attributes for '%@'", path); @@ -2250,10 +2250,10 @@ failure: { [aCoder encodeBytes: bytes length: length - forKey: @"NS.data"]; + forKey: @"NS.data"]; } else - { + { [aCoder encodeValueOfObjCType: @encode(NSUInteger) at: &length]; if (length) @@ -2285,18 +2285,18 @@ failure: data = [aCoder decodeBytesForKey: @"NS.data" - returnedLength: &l]; + returnedLength: &l]; self = [self initWithBytes: data length: l]; } else - { + { NSUInteger l; [aCoder decodeValueOfObjCType: @encode(NSUInteger) at: &l]; if (l) { void *b; - + #if GS_WITH_GC b = NSAllocateCollectable(l, 0); #else @@ -3409,7 +3409,7 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos) } @end #endif - + #ifdef HAVE_MMAP @implementation NSDataMappedFile @@ -3443,14 +3443,14 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos) { off_t off; int fd; - + #if defined(__MINGW__) const unichar *thePath = (const unichar*)[path fileSystemRepresentation]; #else const char *thePath = [path fileSystemRepresentation]; #endif - if (thePath == 0) + if (thePath == 0) { NSWarnMLog(@"Open (%@) attempt failed - bad path", path); DESTROY(self); @@ -4249,7 +4249,7 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos) } @end #endif - + #ifdef HAVE_SHMCTL @implementation NSMutableDataShared @@ -4420,4 +4420,3 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos) @end #endif /* HAVE_SHMCTL */ - diff --git a/Source/NSDictionary.m b/Source/NSDictionary.m index 0d803d653..33c27bd5b 100644 --- a/Source/NSDictionary.m +++ b/Source/NSDictionary.m @@ -863,7 +863,7 @@ static SEL appSel; } - (void)getObjects: (__unsafe_unretained id[])objects - andKeys: (__unsafe_unretained id[])keys + andKeys: (__unsafe_unretained id[])keys { int i=0; FOR_IN(id, key, self) @@ -1242,7 +1242,7 @@ compareIt(id o1, id o2, void* context) if (count > 0) { NSEnumerator *enumerator = [self keyEnumerator]; - NSObject *k; + NSObject *k = nil; while ((k = [enumerator nextObject]) != nil) { diff --git a/Tests/base/NSCache/TestInfo b/Tests/base/NSCache/TestInfo new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/base/NSCache/basic.m b/Tests/base/NSCache/basic.m new file mode 100644 index 000000000..01546cdc3 --- /dev/null +++ b/Tests/base/NSCache/basic.m @@ -0,0 +1,17 @@ +#import "ObjectTesting.h" +#import +#import + +int main() +{ + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + NSCache *testObj; + + testObj = [[NSCache new] autorelease]; + [testObj setObject: @"hello" forKey: @"there"]; + test_alloc(@"NSCache"); + test_NSObject(@"NSCache", [NSArray arrayWithObject: testObj]); + + [arp release]; arp = nil; + return 0; +} diff --git a/Tests/base/NSCache/cache.m b/Tests/base/NSCache/cache.m new file mode 100644 index 000000000..614204d36 --- /dev/null +++ b/Tests/base/NSCache/cache.m @@ -0,0 +1,131 @@ +#import "ObjectTesting.h" +#import +#import + + +@interface TestObject : NSObject +{ + BOOL _discarded; +} +@end + +@implementation TestObject + +- (BOOL)beginContentAccess +{ + return YES; +} + +- (void)endContentAccess +{ +} + +- (void)discardContentIfPossible +{ + _discarded = YES; +} + + + +- (BOOL)isContentDiscarded +{ + return _discarded; +} +@end + +int main() +{ + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + NSCache *cache = [[NSCache new] autorelease]; + + [cache setName: @"Foo"]; + PASS_EQUAL(@"Foo", [cache name], "Name can be set an accessed"); + + [cache setCountLimit: 2]; + PASS(2 == [cache countLimit], "Count limit can be set and accessed"); + + [cache setTotalCostLimit: 3]; + PASS(3 == [cache totalCostLimit], "Total cost limit can be set and accessed"); + + [cache setObject: @"bar" forKey: @"foo"]; + PASS_EQUAL(@"bar", [cache objectForKey: @"foo"], + "Cached object can be returned"); + + + /* + * NOTE: The following to test sets currently won't work. The only available + * eviction strategy is to evict under the following conditions: + * + * - evictsObjectsWithDiscardedContent is set on the receiver + * - the cached object implements NSDiscardableContent + * - the content is actually discarded + */ + START_SET("count-based eviction") + testHopeful = YES; + /* Let's test count based eviction: We add two more items and expect the + * first one (foo) to be removed because the count limit is two + */ + [cache setObject: @"baz" forKey: @"bar"]; + NSUInteger i = 0; + for (i = 0; i < 50; i++) + { + /* We need to heat this object in the cache so that the first one + * becomes elligible for eviction + */ + [cache objectForKey: @"bar"]; + } + [cache setObject: @"frubble" forKey: @"baz"]; + PASS_EQUAL(@"frubble", [cache objectForKey: @"baz"], + "LRU object retained on count overflow"); + PASS_EQUAL(@"baz", [cache objectForKey: @"bar"], + "second object retained on count overflow"); + PASS(nil == [cache objectForKey: @"foo"], "Oldest object evicted"); + END_SET("count-based eviction") + [cache removeAllObjects]; + + START_SET("cost-based eviction") + testHopeful = YES; + [cache setObject: @"bar" forKey: @"foo" cost: 2]; + // This should push out the previous object because the cumulative cost (4) + // exceeds the limit (3) + [cache setObject: @"baz" forKey: @"bar" cost: 2]; + PASS_EQUAL(@"baz", [cache objectForKey: @"bar"], + "LRU object retained on cost overflow"); + PASS(nil == [cache objectForKey: @"foo"], "Overflowing object evicted"); + END_SET("cost-based eviction") + + [cache removeAllObjects]; + START_SET("eviction of discardable content") + cache = [[NSCache new] autorelease]; + [cache setCountLimit: 1]; + [cache setEvictsObjectsWithDiscardedContent: YES]; + TestObject *a = [[TestObject new] autorelease]; + TestObject *b = [[TestObject new] autorelease]; + [cache setObject: a forKey: @"foo"]; + [cache setObject: b forKey: @"bar"]; + PASS_EQUAL(b, [cache objectForKey: @"bar"], + "LRU object retained on count overflow"); + PASS(nil == [cache objectForKey: @"foo"], + "Overflowing object evicted on count overflow"); + + PASS([a isContentDiscarded], + "Cache did call -discardContentIfPossible on cached object"); + [cache removeAllObjects]; + [cache setCountLimit: 0]; + [cache setTotalCostLimit: 3]; + a = [[TestObject new] autorelease]; + b = [[TestObject new] autorelease]; + [cache setObject: a forKey: @"foo" cost: 2]; + [cache setObject: b forKey: @"bar" cost: 2]; + PASS_EQUAL(b, [cache objectForKey: @"bar"], + "LRU object retained on cost overflow"); + PASS(nil == [cache objectForKey: @"foo"], + "Overflowing object evicted on cost overflow"); + PASS([a isContentDiscarded], + "Cache did call -discardContentIfPossible on cached object"); + END_SET("eviction of discardable content") + + + [arp release]; arp = nil; + return 0; +}