diff options
Diffstat (limited to 'libs/cocos2d/Support')
22 files changed, 4245 insertions, 0 deletions
| diff --git a/libs/cocos2d/Support/CCArray.h b/libs/cocos2d/Support/CCArray.h new file mode 100755 index 0000000..0c7b2b8 --- /dev/null +++ b/libs/cocos2d/Support/CCArray.h | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | /* | ||
| 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 ForzeField Studios S.L. http://forzefield.com | ||
| 5 | * | ||
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | * of this software and associated documentation files (the "Software"), to deal | ||
| 8 | * in the Software without restriction, including without limitation the rights | ||
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | * copies of the Software, and to permit persons to whom the Software is | ||
| 11 | * furnished to do so, subject to the following conditions: | ||
| 12 | * | ||
| 13 | * The above copyright notice and this permission notice shall be included in | ||
| 14 | * all copies or substantial portions of the Software. | ||
| 15 | * | ||
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 22 | * THE SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | |||
| 26 | #import "ccCArray.h" | ||
| 27 | |||
| 28 | |||
| 29 | /** A faster alternative of NSArray. | ||
| 30 | CCArray uses internally a c-array. | ||
| 31 | @since v0.99.4 | ||
| 32 | */ | ||
| 33 | |||
| 34 | |||
| 35 | /** @def CCARRAY_FOREACH | ||
| 36 | A convience macro to iterate over a CCArray using. It is faster than the "fast enumeration" interface. | ||
| 37 | @since v0.99.4 | ||
| 38 | */ | ||
| 39 | |||
| 40 | #define CCARRAY_FOREACH(__array__, __object__) \ | ||
| 41 | if (__array__ && __array__->data->num > 0) \ | ||
| 42 | for(id *__arr__ = __array__->data->arr, *end = __array__->data->arr + __array__->data->num-1; \ | ||
| 43 | __arr__ <= end && ((__object__ = *__arr__) != nil || true); \ | ||
| 44 | __arr__++) | ||
| 45 | |||
| 46 | @interface CCArray : NSObject <NSFastEnumeration, NSCoding, NSCopying> | ||
| 47 | { | ||
| 48 | @public ccArray *data; | ||
| 49 | } | ||
| 50 | |||
| 51 | + (id) array; | ||
| 52 | + (id) arrayWithCapacity:(NSUInteger)capacity; | ||
| 53 | + (id) arrayWithArray:(CCArray*)otherArray; | ||
| 54 | + (id) arrayWithNSArray:(NSArray*)otherArray; | ||
| 55 | |||
| 56 | |||
| 57 | - (id) initWithCapacity:(NSUInteger)capacity; | ||
| 58 | - (id) initWithArray:(CCArray*)otherArray; | ||
| 59 | - (id) initWithNSArray:(NSArray*)otherArray; | ||
| 60 | |||
| 61 | |||
| 62 | // Querying an Array | ||
| 63 | |||
| 64 | - (NSUInteger) count; | ||
| 65 | - (NSUInteger) capacity; | ||
| 66 | - (NSUInteger) indexOfObject:(id)object; | ||
| 67 | - (id) objectAtIndex:(NSUInteger)index; | ||
| 68 | - (BOOL) containsObject:(id)object; | ||
| 69 | - (id) randomObject; | ||
| 70 | - (id) lastObject; | ||
| 71 | - (NSArray*) getNSArray; | ||
| 72 | |||
| 73 | |||
| 74 | // Adding Objects | ||
| 75 | |||
| 76 | - (void) addObject:(id)object; | ||
| 77 | - (void) addObjectsFromArray:(CCArray*)otherArray; | ||
| 78 | - (void) addObjectsFromNSArray:(NSArray*)otherArray; | ||
| 79 | - (void) insertObject:(id)object atIndex:(NSUInteger)index; | ||
| 80 | |||
| 81 | |||
| 82 | // Removing Objects | ||
| 83 | |||
| 84 | - (void) removeLastObject; | ||
| 85 | - (void) removeObject:(id)object; | ||
| 86 | - (void) removeObjectAtIndex:(NSUInteger)index; | ||
| 87 | - (void) removeObjectsInArray:(CCArray*)otherArray; | ||
| 88 | - (void) removeAllObjects; | ||
| 89 | - (void) fastRemoveObject:(id)object; | ||
| 90 | - (void) fastRemoveObjectAtIndex:(NSUInteger)index; | ||
| 91 | |||
| 92 | |||
| 93 | // Rearranging Content | ||
| 94 | |||
| 95 | - (void) exchangeObject:(id)object1 withObject:(id)object2; | ||
| 96 | - (void) exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2; | ||
| 97 | - (void) reverseObjects; | ||
| 98 | - (void) reduceMemoryFootprint; | ||
| 99 | |||
| 100 | // Sending Messages to Elements | ||
| 101 | |||
| 102 | - (void) makeObjectsPerformSelector:(SEL)aSelector; | ||
| 103 | - (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)object; | ||
| 104 | |||
| 105 | |||
| 106 | @end | ||
| diff --git a/libs/cocos2d/Support/CCArray.m b/libs/cocos2d/Support/CCArray.m new file mode 100755 index 0000000..a48a5f3 --- /dev/null +++ b/libs/cocos2d/Support/CCArray.m | |||
| @@ -0,0 +1,290 @@ | |||
| 1 | /* | ||
| 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 ForzeField Studios S.L. http://forzefield.com | ||
| 5 | * | ||
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | * of this software and associated documentation files (the "Software"), to deal | ||
| 8 | * in the Software without restriction, including without limitation the rights | ||
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | * copies of the Software, and to permit persons to whom the Software is | ||
| 11 | * furnished to do so, subject to the following conditions: | ||
| 12 | * | ||
| 13 | * The above copyright notice and this permission notice shall be included in | ||
| 14 | * all copies or substantial portions of the Software. | ||
| 15 | * | ||
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 22 | * THE SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #import "CCArray.h" | ||
| 26 | #import "../ccMacros.h" | ||
| 27 | |||
| 28 | |||
| 29 | @implementation CCArray | ||
| 30 | |||
| 31 | + (id) array | ||
| 32 | { | ||
| 33 | return [[[self alloc] init] autorelease]; | ||
| 34 | } | ||
| 35 | |||
| 36 | + (id) arrayWithCapacity:(NSUInteger)capacity | ||
| 37 | { | ||
| 38 | return [[[self alloc] initWithCapacity:capacity] autorelease]; | ||
| 39 | } | ||
| 40 | |||
| 41 | + (id) arrayWithArray:(CCArray*)otherArray | ||
| 42 | { | ||
| 43 | return [[(CCArray*)[self alloc] initWithArray:otherArray] autorelease]; | ||
| 44 | } | ||
| 45 | |||
| 46 | + (id) arrayWithNSArray:(NSArray*)otherArray | ||
| 47 | { | ||
| 48 | return [[(CCArray*)[self alloc] initWithNSArray:otherArray] autorelease]; | ||
| 49 | } | ||
| 50 | |||
| 51 | - (id) init | ||
| 52 | { | ||
| 53 | self = [self initWithCapacity:2]; | ||
| 54 | return self; | ||
| 55 | } | ||
| 56 | |||
| 57 | - (id) initWithCapacity:(NSUInteger)capacity | ||
| 58 | { | ||
| 59 | self = [super init]; | ||
| 60 | if (self != nil) { | ||
| 61 | data = ccArrayNew(capacity); | ||
| 62 | } | ||
| 63 | return self; | ||
| 64 | } | ||
| 65 | |||
| 66 | - (id) initWithArray:(CCArray*)otherArray | ||
| 67 | { | ||
| 68 | self = [self initWithCapacity:otherArray->data->num]; | ||
| 69 | if (self != nil) { | ||
| 70 | [self addObjectsFromArray:otherArray]; | ||
| 71 | } | ||
| 72 | return self; | ||
| 73 | } | ||
| 74 | |||
| 75 | - (id) initWithNSArray:(NSArray*)otherArray | ||
| 76 | { | ||
| 77 | self = [self initWithCapacity:otherArray.count]; | ||
| 78 | if (self != nil) { | ||
| 79 | [self addObjectsFromNSArray:otherArray]; | ||
| 80 | } | ||
| 81 | return self; | ||
| 82 | } | ||
| 83 | |||
| 84 | - (id) initWithCoder:(NSCoder*)coder | ||
| 85 | { | ||
| 86 | self = [self initWithNSArray:[coder decodeObjectForKey:@"nsarray"]]; | ||
| 87 | return self; | ||
| 88 | } | ||
| 89 | |||
| 90 | |||
| 91 | #pragma mark Querying an Array | ||
| 92 | |||
| 93 | - (NSUInteger) count | ||
| 94 | { | ||
| 95 | return data->num; | ||
| 96 | } | ||
| 97 | |||
| 98 | - (NSUInteger) capacity | ||
| 99 | { | ||
| 100 | return data->max; | ||
| 101 | } | ||
| 102 | |||
| 103 | - (NSUInteger) indexOfObject:(id)object | ||
| 104 | { | ||
| 105 | return ccArrayGetIndexOfObject(data, object); | ||
| 106 | } | ||
| 107 | |||
| 108 | - (id) objectAtIndex:(NSUInteger)index | ||
| 109 | { | ||
| 110 | NSAssert2( index < data->num, @"index out of range in objectAtIndex(%d), index %i", data->num, index ); | ||
| 111 | |||
| 112 | return data->arr[index]; | ||
| 113 | } | ||
| 114 | |||
| 115 | - (BOOL) containsObject:(id)object | ||
| 116 | { | ||
| 117 | return ccArrayContainsObject(data, object); | ||
| 118 | } | ||
| 119 | |||
| 120 | - (id) lastObject | ||
| 121 | { | ||
| 122 | if( data->num > 0 ) | ||
| 123 | return data->arr[data->num-1]; | ||
| 124 | return nil; | ||
| 125 | } | ||
| 126 | |||
| 127 | - (id) randomObject | ||
| 128 | { | ||
| 129 | if(data->num==0) return nil; | ||
| 130 | return data->arr[(int)(data->num*CCRANDOM_0_1())]; | ||
| 131 | } | ||
| 132 | |||
| 133 | - (NSArray*) getNSArray | ||
| 134 | { | ||
| 135 | return [NSArray arrayWithObjects:data->arr count:data->num]; | ||
| 136 | } | ||
| 137 | |||
| 138 | |||
| 139 | #pragma mark Adding Objects | ||
| 140 | |||
| 141 | - (void) addObject:(id)object | ||
| 142 | { | ||
| 143 | ccArrayAppendObjectWithResize(data, object); | ||
| 144 | } | ||
| 145 | |||
| 146 | - (void) addObjectsFromArray:(CCArray*)otherArray | ||
| 147 | { | ||
| 148 | ccArrayAppendArrayWithResize(data, otherArray->data); | ||
| 149 | } | ||
| 150 | |||
| 151 | - (void) addObjectsFromNSArray:(NSArray*)otherArray | ||
| 152 | { | ||
| 153 | ccArrayEnsureExtraCapacity(data, otherArray.count); | ||
| 154 | for(id object in otherArray) | ||
| 155 | ccArrayAppendObject(data, object); | ||
| 156 | } | ||
| 157 | |||
| 158 | - (void) insertObject:(id)object atIndex:(NSUInteger)index | ||
| 159 | { | ||
| 160 | ccArrayInsertObjectAtIndex(data, object, index); | ||
| 161 | } | ||
| 162 | |||
| 163 | |||
| 164 | #pragma mark Removing Objects | ||
| 165 | |||
| 166 | - (void) removeObject:(id)object | ||
| 167 | { | ||
| 168 | ccArrayRemoveObject(data, object); | ||
| 169 | } | ||
| 170 | |||
| 171 | - (void) removeObjectAtIndex:(NSUInteger)index | ||
| 172 | { | ||
| 173 | ccArrayRemoveObjectAtIndex(data, index); | ||
| 174 | } | ||
| 175 | |||
| 176 | - (void) fastRemoveObject:(id)object | ||
| 177 | { | ||
| 178 | ccArrayFastRemoveObject(data, object); | ||
| 179 | } | ||
| 180 | |||
| 181 | - (void) fastRemoveObjectAtIndex:(NSUInteger)index | ||
| 182 | { | ||
| 183 | ccArrayFastRemoveObjectAtIndex(data, index); | ||
| 184 | } | ||
| 185 | |||
| 186 | - (void) removeObjectsInArray:(CCArray*)otherArray | ||
| 187 | { | ||
| 188 | ccArrayRemoveArray(data, otherArray->data); | ||
| 189 | } | ||
| 190 | |||
| 191 | - (void) removeLastObject | ||
| 192 | { | ||
| 193 | NSAssert( data->num > 0, @"no objects added" ); | ||
| 194 | |||
| 195 | ccArrayRemoveObjectAtIndex(data, data->num-1); | ||
| 196 | } | ||
| 197 | |||
| 198 | - (void) removeAllObjects | ||
| 199 | { | ||
| 200 | ccArrayRemoveAllObjects(data); | ||
| 201 | } | ||
| 202 | |||
| 203 | |||
| 204 | #pragma mark Rearranging Content | ||
| 205 | |||
| 206 | - (void) exchangeObject:(id)object1 withObject:(id)object2 | ||
| 207 | { | ||
| 208 | NSUInteger index1 = ccArrayGetIndexOfObject(data, object1); | ||
| 209 | if(index1 == NSNotFound) return; | ||
| 210 | NSUInteger index2 = ccArrayGetIndexOfObject(data, object2); | ||
| 211 | if(index2 == NSNotFound) return; | ||
| 212 | |||
| 213 | ccArraySwapObjectsAtIndexes(data, index1, index2); | ||
| 214 | } | ||
| 215 | |||
| 216 | - (void) exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 | ||
| 217 | { | ||
| 218 | ccArraySwapObjectsAtIndexes(data, index1, index2); | ||
| 219 | } | ||
| 220 | |||
| 221 | - (void) reverseObjects | ||
| 222 | { | ||
| 223 | if (data->num > 1) | ||
| 224 | { | ||
| 225 | //floor it since in case of a oneven number the number of swaps stays the same | ||
| 226 | int count = (int) floorf(data->num/2.f); | ||
| 227 | NSUInteger maxIndex = data->num - 1; | ||
| 228 | |||
| 229 | for (int i = 0; i < count ; i++) | ||
| 230 | { | ||
| 231 | ccArraySwapObjectsAtIndexes(data, i, maxIndex); | ||
| 232 | maxIndex--; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | - (void) reduceMemoryFootprint | ||
| 238 | { | ||
| 239 | ccArrayShrink(data); | ||
| 240 | } | ||
| 241 | |||
| 242 | #pragma mark Sending Messages to Elements | ||
| 243 | |||
| 244 | - (void) makeObjectsPerformSelector:(SEL)aSelector | ||
| 245 | { | ||
| 246 | ccArrayMakeObjectsPerformSelector(data, aSelector); | ||
| 247 | } | ||
| 248 | |||
| 249 | - (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)object | ||
| 250 | { | ||
| 251 | ccArrayMakeObjectsPerformSelectorWithObject(data, aSelector, object); | ||
| 252 | } | ||
| 253 | |||
| 254 | |||
| 255 | #pragma mark CCArray - NSFastEnumeration protocol | ||
| 256 | |||
| 257 | - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len | ||
| 258 | { | ||
| 259 | if(state->state == 1) return 0; | ||
| 260 | |||
| 261 | state->mutationsPtr = (unsigned long *)self; | ||
| 262 | state->itemsPtr = &data->arr[0]; | ||
| 263 | state->state = 1; | ||
| 264 | return data->num; | ||
| 265 | } | ||
| 266 | |||
| 267 | |||
| 268 | #pragma mark CCArray - NSCopying protocol | ||
| 269 | |||
| 270 | - (id)copyWithZone:(NSZone *)zone | ||
| 271 | { | ||
| 272 | NSArray *nsArray = [self getNSArray]; | ||
| 273 | CCArray *newArray = [[[self class] allocWithZone:zone] initWithNSArray:nsArray]; | ||
| 274 | return newArray; | ||
| 275 | } | ||
| 276 | |||
| 277 | - (void) encodeWithCoder:(NSCoder *)coder | ||
| 278 | { | ||
| 279 | [coder encodeObject:[self getNSArray] forKey:@"nsarray"]; | ||
| 280 | } | ||
| 281 | |||
| 282 | #pragma mark | ||
| 283 | |||
| 284 | - (void) dealloc | ||
| 285 | { | ||
| 286 | ccArrayFree(data); | ||
| 287 | [super dealloc]; | ||
| 288 | } | ||
| 289 | |||
| 290 | @end | ||
| diff --git a/libs/cocos2d/Support/CCFileUtils.h b/libs/cocos2d/Support/CCFileUtils.h new file mode 100755 index 0000000..0455202 --- /dev/null +++ b/libs/cocos2d/Support/CCFileUtils.h | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | /* | ||
| 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
| 5 | * Copyright (c) 2011 Zynga Inc. | ||
| 6 | * | ||
| 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 8 | * of this software and associated documentation files (the "Software"), to deal | ||
| 9 | * in the Software without restriction, including without limitation the rights | ||
| 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 11 | * copies of the Software, and to permit persons to whom the Software is | ||
| 12 | * furnished to do so, subject to the following conditions: | ||
| 13 | * | ||
| 14 | * The above copyright notice and this permission notice shall be included in | ||
| 15 | * all copies or substantial portions of the Software. | ||
| 16 | * | ||
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 23 | * THE SOFTWARE. | ||
| 24 | * | ||
| 25 | */ | ||
| 26 | |||
| 27 | |||
| 28 | #import <Foundation/Foundation.h> | ||
| 29 | |||
| 30 | |||
| 31 | /** Helper class to handle file operations */ | ||
| 32 | @interface CCFileUtils : NSObject | ||
| 33 | { | ||
| 34 | } | ||
| 35 | |||
| 36 | /** Returns the fullpath of an filename. | ||
| 37 | |||
| 38 | If this method is when Retina Display is enabled, then the | ||
| 39 | Retina Display suffix will be appended to the file (See ccConfig.h). | ||
| 40 | |||
| 41 | If the Retina Display image doesn't exist, then it will return the "non-Retina Display" image | ||
| 42 | |||
| 43 | */ | ||
| 44 | +(NSString*) fullPathFromRelativePath:(NSString*) relPath; | ||
| 45 | @end | ||
| 46 | |||
| 47 | /** loads a file into memory. | ||
| 48 | the caller should release the allocated buffer. | ||
| 49 | |||
| 50 | @returns the size of the allocated buffer | ||
| 51 | @since v0.99.5 | ||
| 52 | */ | ||
| 53 | NSInteger ccLoadFileIntoMemory(const char *filename, unsigned char **out); | ||
| 54 | |||
| 55 | |||
| 56 | /** removes the HD suffix from a path | ||
| 57 | |||
| 58 | @returns NSString * without the HD suffix | ||
| 59 | @since v0.99.5 | ||
| 60 | */ | ||
| 61 | NSString *ccRemoveHDSuffixFromFile( NSString *path ); | ||
| 62 | |||
| diff --git a/libs/cocos2d/Support/CCFileUtils.m b/libs/cocos2d/Support/CCFileUtils.m new file mode 100755 index 0000000..6d33799 --- /dev/null +++ b/libs/cocos2d/Support/CCFileUtils.m | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | /* | ||
| 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
| 5 | * Copyright (c) 2011 Zynga Inc. | ||
| 6 | * | ||
| 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 8 | * of this software and associated documentation files (the "Software"), to deal | ||
| 9 | * in the Software without restriction, including without limitation the rights | ||
| 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 11 | * copies of the Software, and to permit persons to whom the Software is | ||
| 12 | * furnished to do so, subject to the following conditions: | ||
| 13 | * | ||
| 14 | * The above copyright notice and this permission notice shall be included in | ||
| 15 | * all copies or substantial portions of the Software. | ||
| 16 | * | ||
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 23 | * THE SOFTWARE. | ||
| 24 | * | ||
| 25 | */ | ||
| 26 | |||
| 27 | |||
| 28 | #import <Availability.h> | ||
| 29 | #import "CCFileUtils.h" | ||
| 30 | #import "../CCConfiguration.h" | ||
| 31 | #import "../ccMacros.h" | ||
| 32 | #import "../ccConfig.h" | ||
| 33 | |||
| 34 | static NSFileManager *__localFileManager=nil; | ||
| 35 | |||
| 36 | // | ||
| 37 | NSInteger ccLoadFileIntoMemory(const char *filename, unsigned char **out) | ||
| 38 | { | ||
| 39 | NSCAssert( out, @"ccLoadFileIntoMemory: invalid 'out' parameter"); | ||
| 40 | NSCAssert( &*out, @"ccLoadFileIntoMemory: invalid 'out' parameter"); | ||
| 41 | |||
| 42 | size_t size = 0; | ||
| 43 | FILE *f = fopen(filename, "rb"); | ||
| 44 | if( !f ) { | ||
| 45 | *out = NULL; | ||
| 46 | return -1; | ||
| 47 | } | ||
| 48 | |||
| 49 | fseek(f, 0, SEEK_END); | ||
| 50 | size = ftell(f); | ||
| 51 | fseek(f, 0, SEEK_SET); | ||
| 52 | |||
| 53 | *out = malloc(size); | ||
| 54 | size_t read = fread(*out, 1, size, f); | ||
| 55 | if( read != size ) { | ||
| 56 | free(*out); | ||
| 57 | *out = NULL; | ||
| 58 | return -1; | ||
| 59 | } | ||
| 60 | |||
| 61 | fclose(f); | ||
| 62 | |||
| 63 | return size; | ||
| 64 | } | ||
| 65 | |||
| 66 | NSString *ccRemoveHDSuffixFromFile( NSString *path ) | ||
| 67 | { | ||
| 68 | #if CC_IS_RETINA_DISPLAY_SUPPORTED | ||
| 69 | |||
| 70 | if( CC_CONTENT_SCALE_FACTOR() == 2 ) { | ||
| 71 | |||
| 72 | NSString *name = [path lastPathComponent]; | ||
| 73 | |||
| 74 | // check if path already has the suffix. | ||
| 75 | if( [name rangeOfString:CC_RETINA_DISPLAY_FILENAME_SUFFIX].location != NSNotFound ) { | ||
| 76 | |||
| 77 | CCLOG(@"cocos2d: Filename(%@) contains %@ suffix. Removing it. See cocos2d issue #1040", path, CC_RETINA_DISPLAY_FILENAME_SUFFIX); | ||
| 78 | |||
| 79 | NSString *newLastname = [name stringByReplacingOccurrencesOfString:CC_RETINA_DISPLAY_FILENAME_SUFFIX withString:@""]; | ||
| 80 | |||
| 81 | NSString *pathWithoutLastname = [path stringByDeletingLastPathComponent]; | ||
| 82 | return [pathWithoutLastname stringByAppendingPathComponent:newLastname]; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | #endif // CC_IS_RETINA_DISPLAY_SUPPORTED | ||
| 87 | |||
| 88 | return path; | ||
| 89 | |||
| 90 | } | ||
| 91 | |||
| 92 | |||
| 93 | @implementation CCFileUtils | ||
| 94 | |||
| 95 | +(void) initialize | ||
| 96 | { | ||
| 97 | if( self == [CCFileUtils class] ) | ||
| 98 | __localFileManager = [[NSFileManager alloc] init]; | ||
| 99 | } | ||
| 100 | |||
| 101 | +(NSString*) getDoubleResolutionImage:(NSString*)path | ||
| 102 | { | ||
| 103 | #if CC_IS_RETINA_DISPLAY_SUPPORTED | ||
| 104 | |||
| 105 | if( CC_CONTENT_SCALE_FACTOR() == 2 ) | ||
| 106 | { | ||
| 107 | |||
| 108 | NSString *pathWithoutExtension = [path stringByDeletingPathExtension]; | ||
| 109 | NSString *name = [pathWithoutExtension lastPathComponent]; | ||
| 110 | |||
| 111 | // check if path already has the suffix. | ||
| 112 | if( [name rangeOfString:CC_RETINA_DISPLAY_FILENAME_SUFFIX].location != NSNotFound ) { | ||
| 113 | |||
| 114 | CCLOG(@"cocos2d: WARNING Filename(%@) already has the suffix %@. Using it.", name, CC_RETINA_DISPLAY_FILENAME_SUFFIX); | ||
| 115 | return path; | ||
| 116 | } | ||
| 117 | |||
| 118 | |||
| 119 | NSString *extension = [path pathExtension]; | ||
| 120 | |||
| 121 | if( [extension isEqualToString:@"ccz"] || [extension isEqualToString:@"gz"] ) | ||
| 122 | { | ||
| 123 | // All ccz / gz files should be in the format filename.xxx.ccz | ||
| 124 | // so we need to pull off the .xxx part of the extension as well | ||
| 125 | extension = [NSString stringWithFormat:@"%@.%@", [pathWithoutExtension pathExtension], extension]; | ||
| 126 | pathWithoutExtension = [pathWithoutExtension stringByDeletingPathExtension]; | ||
| 127 | } | ||
| 128 | |||
| 129 | |||
| 130 | NSString *retinaName = [pathWithoutExtension stringByAppendingString:CC_RETINA_DISPLAY_FILENAME_SUFFIX]; | ||
| 131 | retinaName = [retinaName stringByAppendingPathExtension:extension]; | ||
| 132 | |||
| 133 | if( [__localFileManager fileExistsAtPath:retinaName] ) | ||
| 134 | return retinaName; | ||
| 135 | |||
| 136 | CCLOG(@"cocos2d: CCFileUtils: Warning HD file not found: %@", [retinaName lastPathComponent] ); | ||
| 137 | } | ||
| 138 | |||
| 139 | #endif // CC_IS_RETINA_DISPLAY_SUPPORTED | ||
| 140 | |||
| 141 | return path; | ||
| 142 | } | ||
| 143 | |||
| 144 | +(NSString*) fullPathFromRelativePath:(NSString*) relPath | ||
| 145 | { | ||
| 146 | NSAssert(relPath != nil, @"CCFileUtils: Invalid path"); | ||
| 147 | |||
| 148 | NSString *fullpath = nil; | ||
| 149 | |||
| 150 | // only if it is not an absolute path | ||
| 151 | if( ! [relPath isAbsolutePath] ) | ||
| 152 | { | ||
| 153 | NSString *file = [relPath lastPathComponent]; | ||
| 154 | NSString *imageDirectory = [relPath stringByDeletingLastPathComponent]; | ||
| 155 | |||
| 156 | fullpath = [[NSBundle mainBundle] pathForResource:file | ||
| 157 | ofType:nil | ||
| 158 | inDirectory:imageDirectory]; | ||
| 159 | } | ||
| 160 | |||
| 161 | if (fullpath == nil) | ||
| 162 | fullpath = relPath; | ||
| 163 | |||
| 164 | fullpath = [self getDoubleResolutionImage:fullpath]; | ||
| 165 | |||
| 166 | return fullpath; | ||
| 167 | } | ||
| 168 | |||
| 169 | @end | ||
| diff --git a/libs/cocos2d/Support/CCProfiling.h b/libs/cocos2d/Support/CCProfiling.h new file mode 100755 index 0000000..b241fb9 --- /dev/null +++ b/libs/cocos2d/Support/CCProfiling.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /* | ||
| 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Stuart Carnie | ||
| 5 | * | ||
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | * of this software and associated documentation files (the "Software"), to deal | ||
| 8 | * in the Software without restriction, including without limitation the rights | ||
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | * copies of the Software, and to permit persons to whom the Software is | ||
| 11 | * furnished to do so, subject to the following conditions: | ||
| 12 | * | ||
| 13 | * The above copyright notice and this permission notice shall be included in | ||
| 14 | * all copies or substantial portions of the Software. | ||
| 15 | * | ||
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 22 | * THE SOFTWARE. | ||
| 23 | * | ||
| 24 | */ | ||
| 25 | |||
| 26 | |||
| 27 | #import <Foundation/Foundation.h> | ||
| 28 | #import <sys/time.h> | ||
| 29 | |||
| 30 | @class CCProfilingTimer; | ||
| 31 | |||
| 32 | @interface CCProfiler : NSObject { | ||
| 33 | NSMutableArray* activeTimers; | ||
| 34 | } | ||
| 35 | |||
| 36 | + (CCProfiler*)sharedProfiler; | ||
| 37 | + (CCProfilingTimer*)timerWithName:(NSString*)timerName andInstance:(id)instance; | ||
| 38 | + (void)releaseTimer:(CCProfilingTimer*)timer; | ||
| 39 | - (void)displayTimers; | ||
| 40 | |||
| 41 | @end | ||
| 42 | |||
| 43 | |||
| 44 | @interface CCProfilingTimer : NSObject { | ||
| 45 | NSString* name; | ||
| 46 | struct timeval startTime; | ||
| 47 | double averageTime; | ||
| 48 | } | ||
| 49 | |||
| 50 | @end | ||
| 51 | |||
| 52 | extern void CCProfilingBeginTimingBlock(CCProfilingTimer* timer); | ||
| 53 | extern void CCProfilingEndTimingBlock(CCProfilingTimer* timer); | ||
| diff --git a/libs/cocos2d/Support/CCProfiling.m b/libs/cocos2d/Support/CCProfiling.m new file mode 100755 index 0000000..13c8c81 --- /dev/null +++ b/libs/cocos2d/Support/CCProfiling.m | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | /* | ||
| 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Stuart Carnie | ||
| 5 | * | ||
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | * of this software and associated documentation files (the "Software"), to deal | ||
| 8 | * in the Software without restriction, including without limitation the rights | ||
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | * copies of the Software, and to permit persons to whom the Software is | ||
| 11 | * furnished to do so, subject to the following conditions: | ||
| 12 | * | ||
| 13 | * The above copyright notice and this permission notice shall be included in | ||
| 14 | * all copies or substantial portions of the Software. | ||
| 15 | * | ||
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 22 | * THE SOFTWARE. | ||
| 23 | * | ||
| 24 | */ | ||
| 25 | |||
| 26 | #import "../ccConfig.h" | ||
| 27 | |||
| 28 | #if CC_ENABLE_PROFILERS | ||
| 29 | |||
| 30 | #import "CCProfiling.h" | ||
| 31 | |||
| 32 | @interface CCProfilingTimer() | ||
| 33 | - (id)initWithName:(NSString*)timerName andInstance:(id)instance; | ||
| 34 | @end | ||
| 35 | |||
| 36 | @implementation CCProfiler | ||
| 37 | |||
| 38 | static CCProfiler* g_sharedProfiler; | ||
| 39 | |||
| 40 | + (CCProfiler*)sharedProfiler { | ||
| 41 | if (!g_sharedProfiler) | ||
| 42 | g_sharedProfiler = [[CCProfiler alloc] init]; | ||
| 43 | |||
| 44 | return g_sharedProfiler; | ||
| 45 | } | ||
| 46 | |||
| 47 | + (CCProfilingTimer*)timerWithName:(NSString*)timerName andInstance:(id)instance { | ||
| 48 | CCProfiler* p = [CCProfiler sharedProfiler]; | ||
| 49 | CCProfilingTimer* t = [[CCProfilingTimer alloc] initWithName:timerName andInstance:instance]; | ||
| 50 | [p->activeTimers addObject:t]; | ||
| 51 | [t release]; | ||
| 52 | return t; | ||
| 53 | } | ||
| 54 | |||
| 55 | + (void)releaseTimer:(CCProfilingTimer*)timer { | ||
| 56 | CCProfiler* p = [CCProfiler sharedProfiler]; | ||
| 57 | [p->activeTimers removeObject:timer]; | ||
| 58 | } | ||
| 59 | |||
| 60 | - (id)init { | ||
| 61 | if (!(self = [super init])) return nil; | ||
| 62 | |||
| 63 | activeTimers = [[NSMutableArray alloc] init]; | ||
| 64 | |||
| 65 | return self; | ||
| 66 | } | ||
| 67 | |||
| 68 | - (void)dealloc { | ||
| 69 | [activeTimers release]; | ||
| 70 | [super dealloc]; | ||
| 71 | } | ||
| 72 | |||
| 73 | - (void)displayTimers { | ||
| 74 | for (id timer in activeTimers) { | ||
| 75 | printf("%s\n", [[timer description] cStringUsingEncoding:[NSString defaultCStringEncoding]]); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | @end | ||
| 80 | |||
| 81 | @implementation CCProfilingTimer | ||
| 82 | |||
| 83 | - (id)initWithName:(NSString*)timerName andInstance:(id)instance { | ||
| 84 | if (!(self = [super init])) return nil; | ||
| 85 | |||
| 86 | name = [[NSString stringWithFormat:@"%@ (0x%.8x)", timerName, instance] retain]; | ||
| 87 | |||
| 88 | return self; | ||
| 89 | } | ||
| 90 | |||
| 91 | - (void)dealloc { | ||
| 92 | [name release]; | ||
| 93 | [super dealloc]; | ||
| 94 | } | ||
| 95 | |||
| 96 | - (NSString*)description { | ||
| 97 | return [NSString stringWithFormat:@"%@ : avg time, %fms", name, averageTime]; | ||
| 98 | } | ||
| 99 | |||
| 100 | void CCProfilingBeginTimingBlock(CCProfilingTimer* timer) { | ||
| 101 | gettimeofday(&timer->startTime, NULL); | ||
| 102 | } | ||
| 103 | |||
| 104 | typedef unsigned int uint32; | ||
| 105 | void CCProfilingEndTimingBlock(CCProfilingTimer* timer) { | ||
| 106 | struct timeval currentTime; | ||
| 107 | gettimeofday(¤tTime, NULL); | ||
| 108 | timersub(¤tTime, &timer->startTime, ¤tTime); | ||
| 109 | double duration = currentTime.tv_sec * 1000.0 + currentTime.tv_usec / 1000.0; | ||
| 110 | |||
| 111 | // return in milliseconds | ||
| 112 | timer->averageTime = (timer->averageTime + duration) / 2.0f; | ||
| 113 | } | ||
| 114 | |||
| 115 | @end | ||
| 116 | |||
| 117 | #endif | ||
| diff --git a/libs/cocos2d/Support/CGPointExtension.h b/libs/cocos2d/Support/CGPointExtension.h new file mode 100755 index 0000000..96edeb7 --- /dev/null +++ b/libs/cocos2d/Support/CGPointExtension.h | |||
| @@ -0,0 +1,334 @@ | |||
| 1 | /* cocos2d for iPhone | ||
| 2 | * http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | * Copyright (c) 2007 Scott Lembcke | ||
| 5 | * | ||
| 6 | * Copyright (c) 2010 Lam Pham | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 9 | * of this software and associated documentation files (the "Software"), to deal | ||
| 10 | * in the Software without restriction, including without limitation the rights | ||
| 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 12 | * copies of the Software, and to permit persons to whom the Software is | ||
| 13 | * furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice shall be included in | ||
| 16 | * all copies or substantial portions of the Software. | ||
| 17 | * | ||
| 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 24 | * SOFTWARE. | ||
| 25 | */ | ||
| 26 | |||
| 27 | /* | ||
| 28 | * Some of the functions were based on Chipmunk's cpVect.h. | ||
| 29 | */ | ||
| 30 | |||
| 31 | /** | ||
| 32 | @file | ||
| 33 | CGPoint extensions based on Chipmunk's cpVect file. | ||
| 34 | These extensions work both with CGPoint and cpVect. | ||
| 35 | |||
| 36 | The "ccp" prefix means: "CoCos2d Point" | ||
| 37 | |||
| 38 | Examples: | ||
| 39 | - ccpAdd( ccp(1,1), ccp(2,2) ); // preferred cocos2d way | ||
| 40 | - ccpAdd( CGPointMake(1,1), CGPointMake(2,2) ); // also ok but more verbose | ||
| 41 | |||
| 42 | - cpvadd( cpv(1,1), cpv(2,2) ); // way of the chipmunk | ||
| 43 | - ccpAdd( cpv(1,1), cpv(2,2) ); // mixing chipmunk and cocos2d (avoid) | ||
| 44 | - cpvadd( CGPointMake(1,1), CGPointMake(2,2) ); // mixing chipmunk and CG (avoid) | ||
| 45 | */ | ||
| 46 | |||
| 47 | #import <Availability.h> | ||
| 48 | |||
| 49 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
| 50 | #import <CoreGraphics/CGGeometry.h> | ||
| 51 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
| 52 | #import <Foundation/Foundation.h> | ||
| 53 | #endif | ||
| 54 | |||
| 55 | #import <math.h> | ||
| 56 | #import <objc/objc.h> | ||
| 57 | |||
| 58 | #ifdef __cplusplus | ||
| 59 | extern "C" { | ||
| 60 | #endif | ||
| 61 | |||
| 62 | /** Helper macro that creates a CGPoint | ||
| 63 | @return CGPoint | ||
| 64 | @since v0.7.2 | ||
| 65 | */ | ||
| 66 | #define ccp(__X__,__Y__) CGPointMake(__X__,__Y__) | ||
| 67 | |||
| 68 | |||
| 69 | /** Returns opposite of point. | ||
| 70 | @return CGPoint | ||
| 71 | @since v0.7.2 | ||
| 72 | */ | ||
| 73 | static inline CGPoint | ||
| 74 | ccpNeg(const CGPoint v) | ||
| 75 | { | ||
| 76 | return ccp(-v.x, -v.y); | ||
| 77 | } | ||
| 78 | |||
| 79 | /** Calculates sum of two points. | ||
| 80 | @return CGPoint | ||
| 81 | @since v0.7.2 | ||
| 82 | */ | ||
| 83 | static inline CGPoint | ||
| 84 | ccpAdd(const CGPoint v1, const CGPoint v2) | ||
| 85 | { | ||
| 86 | return ccp(v1.x + v2.x, v1.y + v2.y); | ||
| 87 | } | ||
| 88 | |||
| 89 | /** Calculates difference of two points. | ||
| 90 | @return CGPoint | ||
| 91 | @since v0.7.2 | ||
| 92 | */ | ||
| 93 | static inline CGPoint | ||
| 94 | ccpSub(const CGPoint v1, const CGPoint v2) | ||
| 95 | { | ||
| 96 | return ccp(v1.x - v2.x, v1.y - v2.y); | ||
| 97 | } | ||
| 98 | |||
| 99 | /** Returns point multiplied by given factor. | ||
| 100 | @return CGPoint | ||
| 101 | @since v0.7.2 | ||
| 102 | */ | ||
| 103 | static inline CGPoint | ||
| 104 | ccpMult(const CGPoint v, const CGFloat s) | ||
| 105 | { | ||
| 106 | return ccp(v.x*s, v.y*s); | ||
| 107 | } | ||
| 108 | |||
| 109 | /** Calculates midpoint between two points. | ||
| 110 | @return CGPoint | ||
| 111 | @since v0.7.2 | ||
| 112 | */ | ||
| 113 | static inline CGPoint | ||
| 114 | ccpMidpoint(const CGPoint v1, const CGPoint v2) | ||
| 115 | { | ||
| 116 | return ccpMult(ccpAdd(v1, v2), 0.5f); | ||
| 117 | } | ||
| 118 | |||
| 119 | /** Calculates dot product of two points. | ||
| 120 | @return CGFloat | ||
| 121 | @since v0.7.2 | ||
| 122 | */ | ||
| 123 | static inline CGFloat | ||
| 124 | ccpDot(const CGPoint v1, const CGPoint v2) | ||
| 125 | { | ||
| 126 | return v1.x*v2.x + v1.y*v2.y; | ||
| 127 | } | ||
| 128 | |||
| 129 | /** Calculates cross product of two points. | ||
| 130 | @return CGFloat | ||
| 131 | @since v0.7.2 | ||
| 132 | */ | ||
| 133 | static inline CGFloat | ||
| 134 | ccpCross(const CGPoint v1, const CGPoint v2) | ||
| 135 | { | ||
| 136 | return v1.x*v2.y - v1.y*v2.x; | ||
| 137 | } | ||
| 138 | |||
| 139 | /** Calculates perpendicular of v, rotated 90 degrees counter-clockwise -- cross(v, perp(v)) >= 0 | ||
| 140 | @return CGPoint | ||
| 141 | @since v0.7.2 | ||
| 142 | */ | ||
| 143 | static inline CGPoint | ||
| 144 | ccpPerp(const CGPoint v) | ||
| 145 | { | ||
| 146 | return ccp(-v.y, v.x); | ||
| 147 | } | ||
| 148 | |||
| 149 | /** Calculates perpendicular of v, rotated 90 degrees clockwise -- cross(v, rperp(v)) <= 0 | ||
| 150 | @return CGPoint | ||
| 151 | @since v0.7.2 | ||
| 152 | */ | ||
| 153 | static inline CGPoint | ||
| 154 | ccpRPerp(const CGPoint v) | ||
| 155 | { | ||
| 156 | return ccp(v.y, -v.x); | ||
| 157 | } | ||
| 158 | |||
| 159 | /** Calculates the projection of v1 over v2. | ||
| 160 | @return CGPoint | ||
| 161 | @since v0.7.2 | ||
| 162 | */ | ||
| 163 | static inline CGPoint | ||
| 164 | ccpProject(const CGPoint v1, const CGPoint v2) | ||
| 165 | { | ||
| 166 | return ccpMult(v2, ccpDot(v1, v2)/ccpDot(v2, v2)); | ||
| 167 | } | ||
| 168 | |||
| 169 | /** Rotates two points. | ||
| 170 | @return CGPoint | ||
| 171 | @since v0.7.2 | ||
| 172 | */ | ||
| 173 | static inline CGPoint | ||
| 174 | ccpRotate(const CGPoint v1, const CGPoint v2) | ||
| 175 | { | ||
| 176 | return ccp(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x); | ||
| 177 | } | ||
| 178 | |||
| 179 | /** Unrotates two points. | ||
| 180 | @return CGPoint | ||
| 181 | @since v0.7.2 | ||
| 182 | */ | ||
| 183 | static inline CGPoint | ||
| 184 | ccpUnrotate(const CGPoint v1, const CGPoint v2) | ||
| 185 | { | ||
| 186 | return ccp(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y); | ||
| 187 | } | ||
| 188 | |||
| 189 | /** Calculates the square length of a CGPoint (not calling sqrt() ) | ||
| 190 | @return CGFloat | ||
| 191 | @since v0.7.2 | ||
| 192 | */ | ||
| 193 | static inline CGFloat | ||
| 194 | ccpLengthSQ(const CGPoint v) | ||
| 195 | { | ||
| 196 | return ccpDot(v, v); | ||
| 197 | } | ||
| 198 | |||
| 199 | /** Calculates distance between point an origin | ||
| 200 | @return CGFloat | ||
| 201 | @since v0.7.2 | ||
| 202 | */ | ||
| 203 | CGFloat ccpLength(const CGPoint v); | ||
| 204 | |||
| 205 | /** Calculates the distance between two points | ||
| 206 | @return CGFloat | ||
| 207 | @since v0.7.2 | ||
| 208 | */ | ||
| 209 | CGFloat ccpDistance(const CGPoint v1, const CGPoint v2); | ||
| 210 | |||
| 211 | /** Returns point multiplied to a length of 1. | ||
| 212 | @return CGPoint | ||
| 213 | @since v0.7.2 | ||
| 214 | */ | ||
| 215 | CGPoint ccpNormalize(const CGPoint v); | ||
| 216 | |||
| 217 | /** Converts radians to a normalized vector. | ||
| 218 | @return CGPoint | ||
| 219 | @since v0.7.2 | ||
| 220 | */ | ||
| 221 | CGPoint ccpForAngle(const CGFloat a); | ||
| 222 | |||
| 223 | /** Converts a vector to radians. | ||
| 224 | @return CGFloat | ||
| 225 | @since v0.7.2 | ||
| 226 | */ | ||
| 227 | CGFloat ccpToAngle(const CGPoint v); | ||
| 228 | |||
| 229 | |||
| 230 | /** Clamp a value between from and to. | ||
| 231 | @since v0.99.1 | ||
| 232 | */ | ||
| 233 | float clampf(float value, float min_inclusive, float max_inclusive); | ||
| 234 | |||
| 235 | /** Clamp a point between from and to. | ||
| 236 | @since v0.99.1 | ||
| 237 | */ | ||
| 238 | CGPoint ccpClamp(CGPoint p, CGPoint from, CGPoint to); | ||
| 239 | |||
| 240 | /** Quickly convert CGSize to a CGPoint | ||
| 241 | @since v0.99.1 | ||
| 242 | */ | ||
| 243 | CGPoint ccpFromSize(CGSize s); | ||
| 244 | |||
| 245 | /** Run a math operation function on each point component | ||
| 246 | * absf, fllorf, ceilf, roundf | ||
| 247 | * any function that has the signature: float func(float); | ||
| 248 | * For example: let's try to take the floor of x,y | ||
| 249 | * ccpCompOp(p,floorf); | ||
| 250 | @since v0.99.1 | ||
| 251 | */ | ||
| 252 | CGPoint ccpCompOp(CGPoint p, float (*opFunc)(float)); | ||
| 253 | |||
| 254 | /** Linear Interpolation between two points a and b | ||
| 255 | @returns | ||
| 256 | alpha == 0 ? a | ||
| 257 | alpha == 1 ? b | ||
| 258 | otherwise a value between a..b | ||
| 259 | @since v0.99.1 | ||
| 260 | */ | ||
| 261 | CGPoint ccpLerp(CGPoint a, CGPoint b, float alpha); | ||
| 262 | |||
| 263 | |||
| 264 | /** @returns if points have fuzzy equality which means equal with some degree of variance. | ||
| 265 | @since v0.99.1 | ||
| 266 | */ | ||
| 267 | BOOL ccpFuzzyEqual(CGPoint a, CGPoint b, float variance); | ||
| 268 | |||
| 269 | |||
| 270 | /** Multiplies a nd b components, a.x*b.x, a.y*b.y | ||
| 271 | @returns a component-wise multiplication | ||
| 272 | @since v0.99.1 | ||
| 273 | */ | ||
| 274 | CGPoint ccpCompMult(CGPoint a, CGPoint b); | ||
| 275 | |||
| 276 | /** @returns the signed angle in radians between two vector directions | ||
| 277 | @since v0.99.1 | ||
| 278 | */ | ||
| 279 | float ccpAngleSigned(CGPoint a, CGPoint b); | ||
| 280 | |||
| 281 | /** @returns the angle in radians between two vector directions | ||
| 282 | @since v0.99.1 | ||
| 283 | */ | ||
| 284 | float ccpAngle(CGPoint a, CGPoint b); | ||
| 285 | |||
| 286 | /** Rotates a point counter clockwise by the angle around a pivot | ||
| 287 | @param v is the point to rotate | ||
| 288 | @param pivot is the pivot, naturally | ||
| 289 | @param angle is the angle of rotation cw in radians | ||
| 290 | @returns the rotated point | ||
| 291 | @since v0.99.1 | ||
| 292 | */ | ||
| 293 | CGPoint ccpRotateByAngle(CGPoint v, CGPoint pivot, float angle); | ||
| 294 | |||
| 295 | /** A general line-line intersection test | ||
| 296 | @param p1 | ||
| 297 | is the startpoint for the first line P1 = (p1 - p2) | ||
| 298 | @param p2 | ||
| 299 | is the endpoint for the first line P1 = (p1 - p2) | ||
| 300 | @param p3 | ||
| 301 | is the startpoint for the second line P2 = (p3 - p4) | ||
| 302 | @param p4 | ||
| 303 | is the endpoint for the second line P2 = (p3 - p4) | ||
| 304 | @param s | ||
| 305 | is the range for a hitpoint in P1 (pa = p1 + s*(p2 - p1)) | ||
| 306 | @param t | ||
| 307 | is the range for a hitpoint in P3 (pa = p2 + t*(p4 - p3)) | ||
| 308 | @return bool | ||
| 309 | indicating successful intersection of a line | ||
| 310 | note that to truly test intersection for segments we have to make | ||
| 311 | sure that s & t lie within [0..1] and for rays, make sure s & t > 0 | ||
| 312 | the hit point is p3 + t * (p4 - p3); | ||
| 313 | the hit point also is p1 + s * (p2 - p1); | ||
| 314 | @since v0.99.1 | ||
| 315 | */ | ||
| 316 | BOOL ccpLineIntersect(CGPoint p1, CGPoint p2, | ||
| 317 | CGPoint p3, CGPoint p4, | ||
| 318 | float *s, float *t); | ||
| 319 | |||
| 320 | /* | ||
| 321 | ccpSegmentIntersect returns YES if Segment A-B intersects with segment C-D | ||
| 322 | @since v1.0.0 | ||
| 323 | */ | ||
| 324 | BOOL ccpSegmentIntersect(CGPoint A, CGPoint B, CGPoint C, CGPoint D); | ||
| 325 | |||
| 326 | /* | ||
| 327 | ccpIntersectPoint returns the intersection point of line A-B, C-D | ||
| 328 | @since v1.0.0 | ||
| 329 | */ | ||
| 330 | CGPoint ccpIntersectPoint(CGPoint A, CGPoint B, CGPoint C, CGPoint D); | ||
| 331 | |||
| 332 | #ifdef __cplusplus | ||
| 333 | } | ||
| 334 | #endif | ||
| diff --git a/libs/cocos2d/Support/CGPointExtension.m b/libs/cocos2d/Support/CGPointExtension.m new file mode 100755 index 0000000..b06859d --- /dev/null +++ b/libs/cocos2d/Support/CGPointExtension.m | |||
| @@ -0,0 +1,196 @@ | |||
| 1 | /* cocos2d for iPhone | ||
| 2 | * http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | * Copyright (c) 2007 Scott Lembcke | ||
| 5 | * | ||
| 6 | * Copyright (c) 2010 Lam Pham | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 9 | * of this software and associated documentation files (the "Software"), to deal | ||
| 10 | * in the Software without restriction, including without limitation the rights | ||
| 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 12 | * copies of the Software, and to permit persons to whom the Software is | ||
| 13 | * furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice shall be included in | ||
| 16 | * all copies or substantial portions of the Software. | ||
| 17 | * | ||
| 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 24 | * SOFTWARE. | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include "stdio.h" | ||
| 28 | #include "math.h" | ||
| 29 | |||
| 30 | #import "../ccMacros.h" // CC_SWAP | ||
| 31 | #include "CGPointExtension.h" | ||
| 32 | |||
| 33 | #define kCGPointEpsilon FLT_EPSILON | ||
| 34 | |||
| 35 | CGFloat | ||
| 36 | ccpLength(const CGPoint v) | ||
| 37 | { | ||
| 38 | return sqrtf(ccpLengthSQ(v)); | ||
| 39 | } | ||
| 40 | |||
| 41 | CGFloat | ||
| 42 | ccpDistance(const CGPoint v1, const CGPoint v2) | ||
| 43 | { | ||
| 44 | return ccpLength(ccpSub(v1, v2)); | ||
| 45 | } | ||
| 46 | |||
| 47 | CGPoint | ||
| 48 | ccpNormalize(const CGPoint v) | ||
| 49 | { | ||
| 50 | return ccpMult(v, 1.0f/ccpLength(v)); | ||
| 51 | } | ||
| 52 | |||
| 53 | CGPoint | ||
| 54 | ccpForAngle(const CGFloat a) | ||
| 55 | { | ||
| 56 | return ccp(cosf(a), sinf(a)); | ||
| 57 | } | ||
| 58 | |||
| 59 | CGFloat | ||
| 60 | ccpToAngle(const CGPoint v) | ||
| 61 | { | ||
| 62 | return atan2f(v.y, v.x); | ||
| 63 | } | ||
| 64 | |||
| 65 | CGPoint ccpLerp(CGPoint a, CGPoint b, float alpha) | ||
| 66 | { | ||
| 67 | return ccpAdd(ccpMult(a, 1.f - alpha), ccpMult(b, alpha)); | ||
| 68 | } | ||
| 69 | |||
| 70 | float clampf(float value, float min_inclusive, float max_inclusive) | ||
| 71 | { | ||
| 72 | if (min_inclusive > max_inclusive) { | ||
| 73 | CC_SWAP(min_inclusive,max_inclusive); | ||
| 74 | } | ||
| 75 | return value < min_inclusive ? min_inclusive : value < max_inclusive? value : max_inclusive; | ||
| 76 | } | ||
| 77 | |||
| 78 | CGPoint ccpClamp(CGPoint p, CGPoint min_inclusive, CGPoint max_inclusive) | ||
| 79 | { | ||
| 80 | return ccp(clampf(p.x,min_inclusive.x,max_inclusive.x), clampf(p.y, min_inclusive.y, max_inclusive.y)); | ||
| 81 | } | ||
| 82 | |||
| 83 | CGPoint ccpFromSize(CGSize s) | ||
| 84 | { | ||
| 85 | return ccp(s.width, s.height); | ||
| 86 | } | ||
| 87 | |||
| 88 | CGPoint ccpCompOp(CGPoint p, float (*opFunc)(float)) | ||
| 89 | { | ||
| 90 | return ccp(opFunc(p.x), opFunc(p.y)); | ||
| 91 | } | ||
| 92 | |||
| 93 | BOOL ccpFuzzyEqual(CGPoint a, CGPoint b, float var) | ||
| 94 | { | ||
| 95 | if(a.x - var <= b.x && b.x <= a.x + var) | ||
| 96 | if(a.y - var <= b.y && b.y <= a.y + var) | ||
| 97 | return true; | ||
| 98 | return false; | ||
| 99 | } | ||
| 100 | |||
| 101 | CGPoint ccpCompMult(CGPoint a, CGPoint b) | ||
| 102 | { | ||
| 103 | return ccp(a.x * b.x, a.y * b.y); | ||
| 104 | } | ||
| 105 | |||
| 106 | float ccpAngleSigned(CGPoint a, CGPoint b) | ||
| 107 | { | ||
| 108 | CGPoint a2 = ccpNormalize(a); | ||
| 109 | CGPoint b2 = ccpNormalize(b); | ||
| 110 | float angle = atan2f(a2.x * b2.y - a2.y * b2.x, ccpDot(a2, b2)); | ||
| 111 | if( fabs(angle) < kCGPointEpsilon ) return 0.f; | ||
| 112 | return angle; | ||
| 113 | } | ||
| 114 | |||
| 115 | CGPoint ccpRotateByAngle(CGPoint v, CGPoint pivot, float angle) | ||
| 116 | { | ||
| 117 | CGPoint r = ccpSub(v, pivot); | ||
| 118 | float cosa = cosf(angle), sina = sinf(angle); | ||
| 119 | float t = r.x; | ||
| 120 | r.x = t*cosa - r.y*sina + pivot.x; | ||
| 121 | r.y = t*sina + r.y*cosa + pivot.y; | ||
| 122 | return r; | ||
| 123 | } | ||
| 124 | |||
| 125 | |||
| 126 | BOOL ccpSegmentIntersect(CGPoint A, CGPoint B, CGPoint C, CGPoint D) | ||
| 127 | { | ||
| 128 | float S, T; | ||
| 129 | |||
| 130 | if( ccpLineIntersect(A, B, C, D, &S, &T ) | ||
| 131 | && (S >= 0.0f && S <= 1.0f && T >= 0.0f && T <= 1.0f) ) | ||
| 132 | return YES; | ||
| 133 | |||
| 134 | return NO; | ||
| 135 | } | ||
| 136 | |||
| 137 | CGPoint ccpIntersectPoint(CGPoint A, CGPoint B, CGPoint C, CGPoint D) | ||
| 138 | { | ||
| 139 | float S, T; | ||
| 140 | |||
| 141 | if( ccpLineIntersect(A, B, C, D, &S, &T) ) { | ||
| 142 | // Point of intersection | ||
| 143 | CGPoint P; | ||
| 144 | P.x = A.x + S * (B.x - A.x); | ||
| 145 | P.y = A.y + S * (B.y - A.y); | ||
| 146 | return P; | ||
| 147 | } | ||
| 148 | |||
| 149 | return CGPointZero; | ||
| 150 | } | ||
| 151 | |||
| 152 | BOOL ccpLineIntersect(CGPoint A, CGPoint B, | ||
| 153 | CGPoint C, CGPoint D, | ||
| 154 | float *S, float *T) | ||
| 155 | { | ||
| 156 | // FAIL: Line undefined | ||
| 157 | if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) ) return NO; | ||
| 158 | |||
| 159 | const float BAx = B.x - A.x; | ||
| 160 | const float BAy = B.y - A.y; | ||
| 161 | const float DCx = D.x - C.x; | ||
| 162 | const float DCy = D.y - C.y; | ||
| 163 | const float ACx = A.x - C.x; | ||
| 164 | const float ACy = A.y - C.y; | ||
| 165 | |||
| 166 | const float denom = DCy*BAx - DCx*BAy; | ||
| 167 | |||
| 168 | *S = DCx*ACy - DCy*ACx; | ||
| 169 | *T = BAx*ACy - BAy*ACx; | ||
| 170 | |||
| 171 | if (denom == 0) { | ||
| 172 | if (*S == 0 || *T == 0) { | ||
| 173 | // Lines incident | ||
| 174 | return YES; | ||
| 175 | } | ||
| 176 | // Lines parallel and not incident | ||
| 177 | return NO; | ||
| 178 | } | ||
| 179 | |||
| 180 | *S = *S / denom; | ||
| 181 | *T = *T / denom; | ||
| 182 | |||
| 183 | // Point of intersection | ||
| 184 | // CGPoint P; | ||
| 185 | // P.x = A.x + *S * (B.x - A.x); | ||
| 186 | // P.y = A.y + *S * (B.y - A.y); | ||
| 187 | |||
| 188 | return YES; | ||
| 189 | } | ||
| 190 | |||
| 191 | float ccpAngle(CGPoint a, CGPoint b) | ||
| 192 | { | ||
| 193 | float angle = acosf(ccpDot(ccpNormalize(a), ccpNormalize(b))); | ||
| 194 | if( fabs(angle) < kCGPointEpsilon ) return 0.f; | ||
| 195 | return angle; | ||
| 196 | } | ||
| diff --git a/libs/cocos2d/Support/OpenGL_Internal.h b/libs/cocos2d/Support/OpenGL_Internal.h new file mode 100755 index 0000000..4789683 --- /dev/null +++ b/libs/cocos2d/Support/OpenGL_Internal.h | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | /* | ||
| 2 | |||
| 3 | ===== IMPORTANT ===== | ||
| 4 | |||
| 5 | This is sample code demonstrating API, technology or techniques in development. | ||
| 6 | Although this sample code has been reviewed for technical accuracy, it is not | ||
| 7 | final. Apple is supplying this information to help you plan for the adoption of | ||
| 8 | the technologies and programming interfaces described herein. This information | ||
| 9 | is subject to change, and software implemented based on this sample code should | ||
| 10 | be tested with final operating system software and final documentation. Newer | ||
| 11 | versions of this sample code may be provided with future seeds of the API or | ||
| 12 | technology. For information about updates to this and other developer | ||
| 13 | documentation, view the New & Updated sidebars in subsequent documentation | ||
| 14 | seeds. | ||
| 15 | |||
| 16 | ===================== | ||
| 17 | |||
| 18 | File: OpenGL_Internal.h | ||
| 19 | Abstract: This file is included for support purposes and isn't necessary for | ||
| 20 | understanding this sample. | ||
| 21 | |||
| 22 | Version: 1.0 | ||
| 23 | |||
| 24 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. | ||
| 25 | ("Apple") in consideration of your agreement to the following terms, and your | ||
| 26 | use, installation, modification or redistribution of this Apple software | ||
| 27 | constitutes acceptance of these terms. If you do not agree with these terms, | ||
| 28 | please do not use, install, modify or redistribute this Apple software. | ||
| 29 | |||
| 30 | In consideration of your agreement to abide by the following terms, and subject | ||
| 31 | to these terms, Apple grants you a personal, non-exclusive license, under | ||
| 32 | Apple's copyrights in this original Apple software (the "Apple Software"), to | ||
| 33 | use, reproduce, modify and redistribute the Apple Software, with or without | ||
| 34 | modifications, in source and/or binary forms; provided that if you redistribute | ||
| 35 | the Apple Software in its entirety and without modifications, you must retain | ||
| 36 | this notice and the following text and disclaimers in all such redistributions | ||
| 37 | of the Apple Software. | ||
| 38 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used | ||
| 39 | to endorse or promote products derived from the Apple Software without specific | ||
| 40 | prior written permission from Apple. Except as expressly stated in this notice, | ||
| 41 | no other rights or licenses, express or implied, are granted by Apple herein, | ||
| 42 | including but not limited to any patent rights that may be infringed by your | ||
| 43 | derivative works or by other works in which the Apple Software may be | ||
| 44 | incorporated. | ||
| 45 | |||
| 46 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO | ||
| 47 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED | ||
| 48 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
| 49 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN | ||
| 50 | COMBINATION WITH YOUR PRODUCTS. | ||
| 51 | |||
| 52 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR | ||
| 53 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||
| 54 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| 55 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR | ||
| 56 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF | ||
| 57 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF | ||
| 58 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 59 | |||
| 60 | Copyright (C) 2008 Apple Inc. All Rights Reserved. | ||
| 61 | |||
| 62 | */ | ||
| 63 | |||
| 64 | /* Generic error reporting */ | ||
| 65 | #define REPORT_ERROR(__FORMAT__, ...) printf("%s: %s\n", __FUNCTION__, [[NSString stringWithFormat:__FORMAT__, __VA_ARGS__] UTF8String]) | ||
| 66 | |||
| 67 | /* EAGL and GL functions calling wrappers that log on error */ | ||
| 68 | #define CALL_EAGL_FUNCTION(__FUNC__, ...) ({ EAGLError __error = __FUNC__( __VA_ARGS__ ); if(__error != kEAGLErrorSuccess) printf("%s() called from %s returned error %i\n", #__FUNC__, __FUNCTION__, __error); (__error ? NO : YES); }) | ||
| 69 | //#define CHECK_GL_ERROR() ({ GLenum __error = glGetError(); if(__error) printf("OpenGL error 0x%04X in %s\n", __error, __FUNCTION__); (__error ? NO : YES); }) | ||
| 70 | #define CHECK_GL_ERROR() ({ GLenum __error = glGetError(); if(__error) printf("OpenGL error 0x%04X in %s\n", __error, __FUNCTION__); }) | ||
| 71 | |||
| 72 | /* Optional delegate methods support */ | ||
| 73 | #ifndef __DELEGATE_IVAR__ | ||
| 74 | #define __DELEGATE_IVAR__ _delegate | ||
| 75 | #endif | ||
| 76 | #ifndef __DELEGATE_METHODS_IVAR__ | ||
| 77 | #define __DELEGATE_METHODS_IVAR__ _delegateMethods | ||
| 78 | #endif | ||
| 79 | #define TEST_DELEGATE_METHOD_BIT(__BIT__) (self->__DELEGATE_METHODS_IVAR__ & (1 << __BIT__)) | ||
| 80 | #define SET_DELEGATE_METHOD_BIT(__BIT__, __NAME__) { if([self->__DELEGATE_IVAR__ respondsToSelector:@selector(__NAME__)]) self->__DELEGATE_METHODS_IVAR__ |= (1 << __BIT__); else self->__DELEGATE_METHODS_IVAR__ &= ~(1 << __BIT__); } | ||
| diff --git a/libs/cocos2d/Support/TGAlib.h b/libs/cocos2d/Support/TGAlib.h new file mode 100755 index 0000000..247084e --- /dev/null +++ b/libs/cocos2d/Support/TGAlib.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | // | ||
| 2 | // TGA lib for cocos2d-iphone | ||
| 3 | // | ||
| 4 | // sources from: http://www.lighthouse3d.com/opengl/terrain/index.php3?tgasource | ||
| 5 | // | ||
| 6 | |||
| 7 | //#ifndef TGA_LIB | ||
| 8 | //#define TGA_LIB | ||
| 9 | |||
| 10 | /** | ||
| 11 | @file | ||
| 12 | TGA image support | ||
| 13 | */ | ||
| 14 | |||
| 15 | enum { | ||
| 16 | TGA_OK, | ||
| 17 | TGA_ERROR_FILE_OPEN, | ||
| 18 | TGA_ERROR_READING_FILE, | ||
| 19 | TGA_ERROR_INDEXED_COLOR, | ||
| 20 | TGA_ERROR_MEMORY, | ||
| 21 | TGA_ERROR_COMPRESSED_FILE, | ||
| 22 | }; | ||
| 23 | |||
| 24 | /** TGA format */ | ||
| 25 | typedef struct sImageTGA { | ||
| 26 | int status; | ||
| 27 | unsigned char type, pixelDepth; | ||
| 28 | |||
| 29 | /** map width */ | ||
| 30 | short int width; | ||
| 31 | |||
| 32 | /** map height */ | ||
| 33 | short int height; | ||
| 34 | |||
| 35 | /** raw data */ | ||
| 36 | unsigned char *imageData; | ||
| 37 | int flipped; | ||
| 38 | } tImageTGA; | ||
| 39 | |||
| 40 | /// load the image header fields. We only keep those that matter! | ||
| 41 | void tgaLoadHeader(FILE *file, tImageTGA *info); | ||
| 42 | |||
| 43 | /// loads the image pixels. You shouldn't call this function directly | ||
| 44 | void tgaLoadImageData(FILE *file, tImageTGA *info); | ||
| 45 | |||
| 46 | /// this is the function to call when we want to load an image | ||
| 47 | tImageTGA * tgaLoad(const char *filename); | ||
| 48 | |||
| 49 | // /converts RGB to greyscale | ||
| 50 | void tgaRGBtogreyscale(tImageTGA *info); | ||
| 51 | |||
| 52 | /// releases the memory used for the image | ||
| 53 | void tgaDestroy(tImageTGA *info); | ||
| 54 | |||
| 55 | //#endif // TGA_LIB | ||
| diff --git a/libs/cocos2d/Support/TGAlib.m b/libs/cocos2d/Support/TGAlib.m new file mode 100755 index 0000000..11303b4 --- /dev/null +++ b/libs/cocos2d/Support/TGAlib.m | |||
| @@ -0,0 +1,274 @@ | |||
| 1 | // | ||
| 2 | // TGA lib for cocos2d-iphone | ||
| 3 | // | ||
| 4 | // sources from: http://www.lighthouse3d.com/opengl/terrain/index.php3?tgasource | ||
| 5 | // | ||
| 6 | // TGA RLE compression support by Ernesto Corvi | ||
| 7 | |||
| 8 | #include <stdio.h> | ||
| 9 | #include <stdlib.h> | ||
| 10 | #include <string.h> | ||
| 11 | |||
| 12 | #import "TGAlib.h" | ||
| 13 | |||
| 14 | void tgaLoadRLEImageData(FILE *file, tImageTGA *info); | ||
| 15 | void tgaFlipImage( tImageTGA *info ); | ||
| 16 | |||
| 17 | // load the image header fields. We only keep those that matter! | ||
| 18 | void tgaLoadHeader(FILE *file, tImageTGA *info) { | ||
| 19 | unsigned char cGarbage; | ||
| 20 | short int iGarbage; | ||
| 21 | |||
| 22 | fread(&cGarbage, sizeof(unsigned char), 1, file); | ||
| 23 | fread(&cGarbage, sizeof(unsigned char), 1, file); | ||
| 24 | |||
| 25 | // type must be 2 or 3 | ||
| 26 | fread(&info->type, sizeof(unsigned char), 1, file); | ||
| 27 | |||
| 28 | fread(&iGarbage, sizeof(short int), 1, file); | ||
| 29 | fread(&iGarbage, sizeof(short int), 1, file); | ||
| 30 | fread(&cGarbage, sizeof(unsigned char), 1, file); | ||
| 31 | fread(&iGarbage, sizeof(short int), 1, file); | ||
| 32 | fread(&iGarbage, sizeof(short int), 1, file); | ||
| 33 | |||
| 34 | fread(&info->width, sizeof(short int), 1, file); | ||
| 35 | fread(&info->height, sizeof(short int), 1, file); | ||
| 36 | fread(&info->pixelDepth, sizeof(unsigned char), 1, file); | ||
| 37 | |||
| 38 | fread(&cGarbage, sizeof(unsigned char), 1, file); | ||
| 39 | |||
| 40 | info->flipped = 0; | ||
| 41 | if ( cGarbage & 0x20 ) info->flipped = 1; | ||
| 42 | } | ||
| 43 | |||
| 44 | // loads the image pixels. You shouldn't call this function directly | ||
| 45 | void tgaLoadImageData(FILE *file, tImageTGA *info) { | ||
| 46 | |||
| 47 | int mode,total,i; | ||
| 48 | unsigned char aux; | ||
| 49 | |||
| 50 | // mode equal the number of components for each pixel | ||
| 51 | mode = info->pixelDepth / 8; | ||
| 52 | // total is the number of unsigned chars we'll have to read | ||
| 53 | total = info->height * info->width * mode; | ||
| 54 | |||
| 55 | fread(info->imageData,sizeof(unsigned char),total,file); | ||
| 56 | |||
| 57 | // mode=3 or 4 implies that the image is RGB(A). However TGA | ||
| 58 | // stores it as BGR(A) so we'll have to swap R and B. | ||
| 59 | if (mode >= 3) | ||
| 60 | for (i=0; i < total; i+= mode) { | ||
| 61 | aux = info->imageData[i]; | ||
| 62 | info->imageData[i] = info->imageData[i+2]; | ||
| 63 | info->imageData[i+2] = aux; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | // loads the RLE encoded image pixels. You shouldn't call this function directly | ||
| 68 | void tgaLoadRLEImageData(FILE *file, tImageTGA *info) | ||
| 69 | { | ||
| 70 | unsigned int mode,total,i, index = 0; | ||
| 71 | unsigned char aux[4], runlength = 0; | ||
| 72 | unsigned int skip = 0, flag = 0; | ||
| 73 | |||
| 74 | // mode equal the number of components for each pixel | ||
| 75 | mode = info->pixelDepth / 8; | ||
| 76 | // total is the number of unsigned chars we'll have to read | ||
| 77 | total = info->height * info->width; | ||
| 78 | |||
| 79 | for( i = 0; i < total; i++ ) | ||
| 80 | { | ||
| 81 | // if we have a run length pending, run it | ||
| 82 | if ( runlength != 0 ) | ||
| 83 | { | ||
| 84 | // we do, update the run length count | ||
| 85 | runlength--; | ||
| 86 | skip = (flag != 0); | ||
| 87 | } | ||
| 88 | else | ||
| 89 | { | ||
| 90 | // otherwise, read in the run length token | ||
| 91 | if ( fread(&runlength,sizeof(unsigned char),1,file) != 1 ) | ||
| 92 | return; | ||
| 93 | |||
| 94 | // see if it's a RLE encoded sequence | ||
| 95 | flag = runlength & 0x80; | ||
| 96 | if ( flag ) runlength -= 128; | ||
| 97 | skip = 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | // do we need to skip reading this pixel? | ||
| 101 | if ( !skip ) | ||
| 102 | { | ||
| 103 | // no, read in the pixel data | ||
| 104 | if ( fread(aux,sizeof(unsigned char),mode,file) != mode ) | ||
| 105 | return; | ||
| 106 | |||
| 107 | // mode=3 or 4 implies that the image is RGB(A). However TGA | ||
| 108 | // stores it as BGR(A) so we'll have to swap R and B. | ||
| 109 | if ( mode >= 3 ) | ||
| 110 | { | ||
| 111 | unsigned char tmp; | ||
| 112 | |||
| 113 | tmp = aux[0]; | ||
| 114 | aux[0] = aux[2]; | ||
| 115 | aux[2] = tmp; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | // add the pixel to our image | ||
| 120 | memcpy(&info->imageData[index], aux, mode); | ||
| 121 | index += mode; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | void tgaFlipImage( tImageTGA *info ) | ||
| 126 | { | ||
| 127 | // mode equal the number of components for each pixel | ||
| 128 | int mode = info->pixelDepth / 8; | ||
| 129 | int rowbytes = info->width*mode; | ||
| 130 | unsigned char *row = (unsigned char *)malloc(rowbytes); | ||
| 131 | int y; | ||
| 132 | |||
| 133 | if (row == NULL) return; | ||
| 134 | |||
| 135 | for( y = 0; y < (info->height/2); y++ ) | ||
| 136 | { | ||
| 137 | memcpy(row, &info->imageData[y*rowbytes],rowbytes); | ||
| 138 | memcpy(&info->imageData[y*rowbytes], &info->imageData[(info->height-(y+1))*rowbytes], rowbytes); | ||
| 139 | memcpy(&info->imageData[(info->height-(y+1))*rowbytes], row, rowbytes); | ||
| 140 | } | ||
| 141 | |||
| 142 | free(row); | ||
| 143 | info->flipped = 0; | ||
| 144 | } | ||
| 145 | |||
| 146 | // this is the function to call when we want to load an image | ||
| 147 | tImageTGA * tgaLoad(const char *filename) { | ||
| 148 | |||
| 149 | FILE *file; | ||
| 150 | tImageTGA *info; | ||
| 151 | int mode,total; | ||
| 152 | |||
| 153 | // allocate memory for the info struct and check! | ||
| 154 | info = (tImageTGA *)malloc(sizeof(tImageTGA)); | ||
| 155 | if (info == NULL) | ||
| 156 | return(NULL); | ||
| 157 | |||
| 158 | |||
| 159 | // open the file for reading (binary mode) | ||
| 160 | file = fopen(filename, "rb"); | ||
| 161 | if (file == NULL) { | ||
| 162 | info->status = TGA_ERROR_FILE_OPEN; | ||
| 163 | return(info); | ||
| 164 | } | ||
| 165 | |||
| 166 | // load the header | ||
| 167 | tgaLoadHeader(file,info); | ||
| 168 | |||
| 169 | // check for errors when loading the header | ||
| 170 | if (ferror(file)) { | ||
| 171 | info->status = TGA_ERROR_READING_FILE; | ||
| 172 | fclose(file); | ||
| 173 | return(info); | ||
| 174 | } | ||
| 175 | |||
| 176 | // check if the image is color indexed | ||
| 177 | if (info->type == 1) { | ||
| 178 | info->status = TGA_ERROR_INDEXED_COLOR; | ||
| 179 | fclose(file); | ||
| 180 | return(info); | ||
| 181 | } | ||
| 182 | // check for other types (compressed images) | ||
| 183 | if ((info->type != 2) && (info->type !=3) && (info->type !=10) ) { | ||
| 184 | info->status = TGA_ERROR_COMPRESSED_FILE; | ||
| 185 | fclose(file); | ||
| 186 | return(info); | ||
| 187 | } | ||
| 188 | |||
| 189 | // mode equals the number of image components | ||
| 190 | mode = info->pixelDepth / 8; | ||
| 191 | // total is the number of unsigned chars to read | ||
| 192 | total = info->height * info->width * mode; | ||
| 193 | // allocate memory for image pixels | ||
| 194 | info->imageData = (unsigned char *)malloc(sizeof(unsigned char) * | ||
| 195 | total); | ||
| 196 | |||
| 197 | // check to make sure we have the memory required | ||
| 198 | if (info->imageData == NULL) { | ||
| 199 | info->status = TGA_ERROR_MEMORY; | ||
| 200 | fclose(file); | ||
| 201 | return(info); | ||
| 202 | } | ||
| 203 | // finally load the image pixels | ||
| 204 | if ( info->type == 10 ) | ||
| 205 | tgaLoadRLEImageData(file, info); | ||
| 206 | else | ||
| 207 | tgaLoadImageData(file,info); | ||
| 208 | |||
| 209 | // check for errors when reading the pixels | ||
| 210 | if (ferror(file)) { | ||
| 211 | info->status = TGA_ERROR_READING_FILE; | ||
| 212 | fclose(file); | ||
| 213 | return(info); | ||
| 214 | } | ||
| 215 | fclose(file); | ||
| 216 | info->status = TGA_OK; | ||
| 217 | |||
| 218 | if ( info->flipped ) | ||
| 219 | { | ||
| 220 | tgaFlipImage( info ); | ||
| 221 | if ( info->flipped ) info->status = TGA_ERROR_MEMORY; | ||
| 222 | } | ||
| 223 | |||
| 224 | return(info); | ||
| 225 | } | ||
| 226 | |||
| 227 | // converts RGB to greyscale | ||
| 228 | void tgaRGBtogreyscale(tImageTGA *info) { | ||
| 229 | |||
| 230 | int mode,i,j; | ||
| 231 | |||
| 232 | unsigned char *newImageData; | ||
| 233 | |||
| 234 | // if the image is already greyscale do nothing | ||
| 235 | if (info->pixelDepth == 8) | ||
| 236 | return; | ||
| 237 | |||
| 238 | // compute the number of actual components | ||
| 239 | mode = info->pixelDepth / 8; | ||
| 240 | |||
| 241 | // allocate an array for the new image data | ||
| 242 | newImageData = (unsigned char *)malloc(sizeof(unsigned char) * | ||
| 243 | info->height * info->width); | ||
| 244 | if (newImageData == NULL) { | ||
| 245 | return; | ||
| 246 | } | ||
| 247 | |||
| 248 | // convert pixels: greyscale = o.30 * R + 0.59 * G + 0.11 * B | ||
| 249 | for (i = 0,j = 0; j < info->width * info->height; i +=mode, j++) | ||
| 250 | newImageData[j] = | ||
| 251 | (unsigned char)(0.30 * info->imageData[i] + | ||
| 252 | 0.59 * info->imageData[i+1] + | ||
| 253 | 0.11 * info->imageData[i+2]); | ||
| 254 | |||
| 255 | |||
| 256 | //free old image data | ||
| 257 | free(info->imageData); | ||
| 258 | |||
| 259 | // reassign pixelDepth and type according to the new image type | ||
| 260 | info->pixelDepth = 8; | ||
| 261 | info->type = 3; | ||
| 262 | // reassing imageData to the new array. | ||
| 263 | info->imageData = newImageData; | ||
| 264 | } | ||
| 265 | |||
| 266 | // releases the memory used for the image | ||
| 267 | void tgaDestroy(tImageTGA *info) { | ||
| 268 | |||
| 269 | if (info != NULL) { | ||
| 270 | if (info->imageData != NULL) | ||
| 271 | free(info->imageData); | ||
| 272 | free(info); | ||
| 273 | } | ||
| 274 | } | ||
| diff --git a/libs/cocos2d/Support/TransformUtils.h b/libs/cocos2d/Support/TransformUtils.h new file mode 100755 index 0000000..49fde35 --- /dev/null +++ b/libs/cocos2d/Support/TransformUtils.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /* | ||
| 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009 Valentin Milea | ||
| 5 | * | ||
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | * of this software and associated documentation files (the "Software"), to deal | ||
| 8 | * in the Software without restriction, including without limitation the rights | ||
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | * copies of the Software, and to permit persons to whom the Software is | ||
| 11 | * furnished to do so, subject to the following conditions: | ||
| 12 | * | ||
| 13 | * The above copyright notice and this permission notice shall be included in | ||
| 14 | * all copies or substantial portions of the Software. | ||
| 15 | * | ||
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 22 | * THE SOFTWARE. | ||
| 23 | * | ||
| 24 | */ | ||
| 25 | |||
| 26 | #import <Availability.h> | ||
| 27 | |||
| 28 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
| 29 | #import <UIKit/UIKit.h> | ||
| 30 | #import <OpenGLES/ES1/gl.h> | ||
| 31 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
| 32 | #import <OpenGL/gl.h> | ||
| 33 | #import <Foundation/Foundation.h> | ||
| 34 | #endif | ||
| 35 | |||
| 36 | void CGAffineToGL(const CGAffineTransform *t, GLfloat *m); | ||
| 37 | void GLToCGAffine(const GLfloat *m, CGAffineTransform *t); | ||
| diff --git a/libs/cocos2d/Support/TransformUtils.m b/libs/cocos2d/Support/TransformUtils.m new file mode 100755 index 0000000..9caecf0 --- /dev/null +++ b/libs/cocos2d/Support/TransformUtils.m | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* | ||
| 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009 Valentin Milea | ||
| 5 | * | ||
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | * of this software and associated documentation files (the "Software"), to deal | ||
| 8 | * in the Software without restriction, including without limitation the rights | ||
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | * copies of the Software, and to permit persons to whom the Software is | ||
| 11 | * furnished to do so, subject to the following conditions: | ||
| 12 | * | ||
| 13 | * The above copyright notice and this permission notice shall be included in | ||
| 14 | * all copies or substantial portions of the Software. | ||
| 15 | * | ||
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 22 | * THE SOFTWARE. | ||
| 23 | * | ||
| 24 | */ | ||
| 25 | |||
| 26 | |||
| 27 | #import "TransformUtils.h" | ||
| 28 | |||
| 29 | void CGAffineToGL(const CGAffineTransform *t, GLfloat *m) | ||
| 30 | { | ||
| 31 | // | m[0] m[4] m[8] m[12] | | m11 m21 m31 m41 | | a c 0 tx | | ||
| 32 | // | m[1] m[5] m[9] m[13] | | m12 m22 m32 m42 | | b d 0 ty | | ||
| 33 | // | m[2] m[6] m[10] m[14] | <=> | m13 m23 m33 m43 | <=> | 0 0 1 0 | | ||
| 34 | // | m[3] m[7] m[11] m[15] | | m14 m24 m34 m44 | | 0 0 0 1 | | ||
| 35 | |||
| 36 | m[2] = m[3] = m[6] = m[7] = m[8] = m[9] = m[11] = m[14] = 0.0f; | ||
| 37 | m[10] = m[15] = 1.0f; | ||
| 38 | m[0] = t->a; m[4] = t->c; m[12] = t->tx; | ||
| 39 | m[1] = t->b; m[5] = t->d; m[13] = t->ty; | ||
| 40 | } | ||
| 41 | |||
| 42 | void GLToCGAffine(const GLfloat *m, CGAffineTransform *t) | ||
| 43 | { | ||
| 44 | t->a = m[0]; t->c = m[4]; t->tx = m[12]; | ||
| 45 | t->b = m[1]; t->d = m[5]; t->ty = m[13]; | ||
| 46 | } | ||
| diff --git a/libs/cocos2d/Support/ZipUtils.h b/libs/cocos2d/Support/ZipUtils.h new file mode 100755 index 0000000..363f911 --- /dev/null +++ b/libs/cocos2d/Support/ZipUtils.h | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | /* cocos2d for iPhone | ||
| 2 | * | ||
| 3 | * http://www.cocos2d-iphone.org | ||
| 4 | * | ||
| 5 | * | ||
| 6 | * inflateMemory_ based on zlib example code | ||
| 7 | * http://www.zlib.net | ||
| 8 | * | ||
| 9 | * Some ideas were taken from: | ||
| 10 | * http://themanaworld.org/ | ||
| 11 | * from the mapreader.cpp file | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef __CC_ZIP_UTILS_H | ||
| 16 | #define __CC_ZIP_UTILS_H | ||
| 17 | |||
| 18 | #import <stdint.h> | ||
| 19 | |||
| 20 | #ifdef __cplusplus | ||
| 21 | extern "C" { | ||
| 22 | #endif | ||
| 23 | |||
| 24 | /* XXX: pragma pack ??? */ | ||
| 25 | /** @struct CCZHeader | ||
| 26 | */ | ||
| 27 | struct CCZHeader { | ||
| 28 | uint8_t sig[4]; // signature. Should be 'CCZ!' 4 bytes | ||
| 29 | uint16_t compression_type; // should 0 | ||
| 30 | uint16_t version; // should be 2 (although version type==1 is also supported) | ||
| 31 | uint32_t reserved; // Reserverd for users. | ||
| 32 | uint32_t len; // size of the uncompressed file | ||
| 33 | }; | ||
| 34 | |||
| 35 | enum { | ||
| 36 | CCZ_COMPRESSION_ZLIB, // zlib format. | ||
| 37 | CCZ_COMPRESSION_BZIP2, // bzip2 format (not supported yet) | ||
| 38 | CCZ_COMPRESSION_GZIP, // gzip format (not supported yet) | ||
| 39 | CCZ_COMPRESSION_NONE, // plain (not supported yet) | ||
| 40 | }; | ||
| 41 | |||
| 42 | /** @file | ||
| 43 | * Zip helper functions | ||
| 44 | */ | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Inflates either zlib or gzip deflated memory. The inflated memory is | ||
| 48 | * expected to be freed by the caller. | ||
| 49 | * | ||
| 50 | * It will allocate 256k for the destination buffer. If it is not enought it will multiply the previous buffer size per 2, until there is enough memory. | ||
| 51 | * @returns the length of the deflated buffer | ||
| 52 | * | ||
| 53 | @since v0.8.1 | ||
| 54 | */ | ||
| 55 | int ccInflateMemory(unsigned char *in, unsigned int inLength, unsigned char **out); | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Inflates either zlib or gzip deflated memory. The inflated memory is | ||
| 59 | * expected to be freed by the caller. | ||
| 60 | * | ||
| 61 | * outLenghtHint is assumed to be the needed room to allocate the inflated buffer. | ||
| 62 | * | ||
| 63 | * @returns the length of the deflated buffer | ||
| 64 | * | ||
| 65 | @since v1.0.0 | ||
| 66 | */ | ||
| 67 | int ccInflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int outLenghtHint ); | ||
| 68 | |||
| 69 | |||
| 70 | /** inflates a GZip file into memory | ||
| 71 | * | ||
| 72 | * @returns the length of the deflated buffer | ||
| 73 | * | ||
| 74 | * @since v0.99.5 | ||
| 75 | */ | ||
| 76 | int ccInflateGZipFile(const char *filename, unsigned char **out); | ||
| 77 | |||
| 78 | /** inflates a CCZ file into memory | ||
| 79 | * | ||
| 80 | * @returns the length of the deflated buffer | ||
| 81 | * | ||
| 82 | * @since v0.99.5 | ||
| 83 | */ | ||
| 84 | int ccInflateCCZFile(const char *filename, unsigned char **out); | ||
| 85 | |||
| 86 | |||
| 87 | #ifdef __cplusplus | ||
| 88 | } | ||
| 89 | #endif | ||
| 90 | |||
| 91 | #endif // __CC_ZIP_UTILS_H | ||
| diff --git a/libs/cocos2d/Support/ZipUtils.m b/libs/cocos2d/Support/ZipUtils.m new file mode 100755 index 0000000..ccd8bbc --- /dev/null +++ b/libs/cocos2d/Support/ZipUtils.m | |||
| @@ -0,0 +1,251 @@ | |||
| 1 | /* cocos2d for iPhone | ||
| 2 | * | ||
| 3 | * http://www.cocos2d-iphone.org | ||
| 4 | * | ||
| 5 | * | ||
| 6 | * Inflates either zlib or gzip deflated memory. The inflated memory is | ||
| 7 | * expected to be freed by the caller. | ||
| 8 | * | ||
| 9 | * inflateMemory_ based on zlib example code | ||
| 10 | * http://www.zlib.net | ||
| 11 | * | ||
| 12 | * Some ideas were taken from: | ||
| 13 | * http://themanaworld.org/ | ||
| 14 | * from the mapreader.cpp file | ||
| 15 | */ | ||
| 16 | |||
| 17 | #import <Availability.h> | ||
| 18 | |||
| 19 | #import <zlib.h> | ||
| 20 | #import <stdlib.h> | ||
| 21 | #import <assert.h> | ||
| 22 | #import <stdio.h> | ||
| 23 | |||
| 24 | #import "ZipUtils.h" | ||
| 25 | #import "CCFileUtils.h" | ||
| 26 | #import "../ccMacros.h" | ||
| 27 | |||
| 28 | // memory in iPhone is precious | ||
| 29 | // Should buffer factor be 1.5 instead of 2 ? | ||
| 30 | #define BUFFER_INC_FACTOR (2) | ||
| 31 | |||
| 32 | static int inflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int *outLength, unsigned int outLenghtHint ) | ||
| 33 | { | ||
| 34 | /* ret value */ | ||
| 35 | int err = Z_OK; | ||
| 36 | |||
| 37 | int bufferSize = outLenghtHint; | ||
| 38 | *out = (unsigned char*) malloc(bufferSize); | ||
| 39 | |||
| 40 | z_stream d_stream; /* decompression stream */ | ||
| 41 | d_stream.zalloc = (alloc_func)0; | ||
| 42 | d_stream.zfree = (free_func)0; | ||
| 43 | d_stream.opaque = (voidpf)0; | ||
| 44 | |||
| 45 | d_stream.next_in = in; | ||
| 46 | d_stream.avail_in = inLength; | ||
| 47 | d_stream.next_out = *out; | ||
| 48 | d_stream.avail_out = bufferSize; | ||
| 49 | |||
| 50 | /* window size to hold 256k */ | ||
| 51 | if( (err = inflateInit2(&d_stream, 15 + 32)) != Z_OK ) | ||
| 52 | return err; | ||
| 53 | |||
| 54 | for (;;) { | ||
| 55 | err = inflate(&d_stream, Z_NO_FLUSH); | ||
| 56 | |||
| 57 | if (err == Z_STREAM_END) | ||
| 58 | break; | ||
| 59 | |||
| 60 | switch (err) { | ||
| 61 | case Z_NEED_DICT: | ||
| 62 | err = Z_DATA_ERROR; | ||
| 63 | case Z_DATA_ERROR: | ||
| 64 | case Z_MEM_ERROR: | ||
| 65 | inflateEnd(&d_stream); | ||
| 66 | return err; | ||
| 67 | } | ||
| 68 | |||
| 69 | // not enough memory ? | ||
| 70 | if (err != Z_STREAM_END) { | ||
| 71 | |||
| 72 | unsigned char *tmp = realloc(*out, bufferSize * BUFFER_INC_FACTOR); | ||
| 73 | |||
| 74 | /* not enough memory, ouch */ | ||
| 75 | if (! tmp ) { | ||
| 76 | CCLOG(@"cocos2d: ZipUtils: realloc failed"); | ||
| 77 | inflateEnd(&d_stream); | ||
| 78 | return Z_MEM_ERROR; | ||
| 79 | } | ||
| 80 | /* only assign to *out if tmp is valid. it's not guaranteed that realloc will reuse the memory */ | ||
| 81 | *out = tmp; | ||
| 82 | |||
| 83 | d_stream.next_out = *out + bufferSize; | ||
| 84 | d_stream.avail_out = bufferSize; | ||
| 85 | bufferSize *= BUFFER_INC_FACTOR; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | |||
| 90 | *outLength = bufferSize - d_stream.avail_out; | ||
| 91 | err = inflateEnd(&d_stream); | ||
| 92 | return err; | ||
| 93 | } | ||
| 94 | |||
| 95 | int ccInflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int outLengthHint ) | ||
| 96 | { | ||
| 97 | unsigned int outLength = 0; | ||
| 98 | int err = inflateMemoryWithHint(in, inLength, out, &outLength, outLengthHint ); | ||
| 99 | |||
| 100 | if (err != Z_OK || *out == NULL) { | ||
| 101 | if (err == Z_MEM_ERROR) | ||
| 102 | CCLOG(@"cocos2d: ZipUtils: Out of memory while decompressing map data!"); | ||
| 103 | |||
| 104 | else if (err == Z_VERSION_ERROR) | ||
| 105 | CCLOG(@"cocos2d: ZipUtils: Incompatible zlib version!"); | ||
| 106 | |||
| 107 | else if (err == Z_DATA_ERROR) | ||
| 108 | CCLOG(@"cocos2d: ZipUtils: Incorrect zlib compressed data!"); | ||
| 109 | |||
| 110 | else | ||
| 111 | CCLOG(@"cocos2d: ZipUtils: Unknown error while decompressing map data!"); | ||
| 112 | |||
| 113 | free(*out); | ||
| 114 | *out = NULL; | ||
| 115 | outLength = 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | return outLength; | ||
| 119 | } | ||
| 120 | |||
| 121 | int ccInflateMemory(unsigned char *in, unsigned int inLength, unsigned char **out) | ||
| 122 | { | ||
| 123 | // 256k for hint | ||
| 124 | return ccInflateMemoryWithHint(in, inLength, out, 256 * 1024 ); | ||
| 125 | } | ||
| 126 | |||
| 127 | int ccInflateGZipFile(const char *path, unsigned char **out) | ||
| 128 | { | ||
| 129 | int len; | ||
| 130 | unsigned int offset = 0; | ||
| 131 | |||
| 132 | NSCAssert( out, @"ccInflateGZipFile: invalid 'out' parameter"); | ||
| 133 | NSCAssert( &*out, @"ccInflateGZipFile: invalid 'out' parameter"); | ||
| 134 | |||
| 135 | gzFile inFile = gzopen(path, "rb"); | ||
| 136 | if( inFile == NULL ) { | ||
| 137 | CCLOG(@"cocos2d: ZipUtils: error open gzip file: %s", path); | ||
| 138 | return -1; | ||
| 139 | } | ||
| 140 | |||
| 141 | /* 512k initial decompress buffer */ | ||
| 142 | int bufferSize = 512 * 1024; | ||
| 143 | unsigned int totalBufferSize = bufferSize; | ||
| 144 | |||
| 145 | *out = malloc( bufferSize ); | ||
| 146 | if( ! out ) { | ||
| 147 | CCLOG(@"cocos2d: ZipUtils: out of memory"); | ||
| 148 | return -1; | ||
| 149 | } | ||
| 150 | |||
| 151 | for (;;) { | ||
| 152 | len = gzread(inFile, *out + offset, bufferSize); | ||
| 153 | if (len < 0) { | ||
| 154 | CCLOG(@"cocos2d: ZipUtils: error in gzread"); | ||
| 155 | free( *out ); | ||
| 156 | *out = NULL; | ||
| 157 | return -1; | ||
| 158 | } | ||
| 159 | if (len == 0) | ||
| 160 | break; | ||
| 161 | |||
| 162 | offset += len; | ||
| 163 | |||
| 164 | // finish reading the file | ||
| 165 | if( len < bufferSize ) | ||
| 166 | break; | ||
| 167 | |||
| 168 | bufferSize *= BUFFER_INC_FACTOR; | ||
| 169 | totalBufferSize += bufferSize; | ||
| 170 | unsigned char *tmp = realloc(*out, totalBufferSize ); | ||
| 171 | |||
| 172 | if( ! tmp ) { | ||
| 173 | CCLOG(@"cocos2d: ZipUtils: out of memory"); | ||
| 174 | free( *out ); | ||
| 175 | *out = NULL; | ||
| 176 | return -1; | ||
| 177 | } | ||
| 178 | |||
| 179 | *out = tmp; | ||
| 180 | } | ||
| 181 | |||
| 182 | if (gzclose(inFile) != Z_OK) | ||
| 183 | CCLOG(@"cocos2d: ZipUtils: gzclose failed"); | ||
| 184 | |||
| 185 | return offset; | ||
| 186 | } | ||
| 187 | |||
| 188 | int ccInflateCCZFile(const char *path, unsigned char **out) | ||
| 189 | { | ||
| 190 | NSCAssert( out, @"ccInflateCCZFile: invalid 'out' parameter"); | ||
| 191 | NSCAssert( &*out, @"ccInflateCCZFile: invalid 'out' parameter"); | ||
| 192 | |||
| 193 | // load file into memory | ||
| 194 | unsigned char *compressed = NULL; | ||
| 195 | NSInteger fileLen = ccLoadFileIntoMemory( path, &compressed ); | ||
| 196 | if( fileLen < 0 ) { | ||
| 197 | CCLOG(@"cocos2d: Error loading CCZ compressed file"); | ||
| 198 | } | ||
| 199 | |||
| 200 | struct CCZHeader *header = (struct CCZHeader*) compressed; | ||
| 201 | |||
| 202 | // verify header | ||
| 203 | if( header->sig[0] != 'C' || header->sig[1] != 'C' || header->sig[2] != 'Z' || header->sig[3] != '!' ) { | ||
| 204 | CCLOG(@"cocos2d: Invalid CCZ file"); | ||
| 205 | free(compressed); | ||
| 206 | return -1; | ||
| 207 | } | ||
| 208 | |||
| 209 | // verify header version | ||
| 210 | uint16_t version = CFSwapInt16BigToHost( header->version ); | ||
| 211 | if( version > 2 ) { | ||
| 212 | CCLOG(@"cocos2d: Unsupported CCZ header format"); | ||
| 213 | free(compressed); | ||
| 214 | return -1; | ||
| 215 | } | ||
| 216 | |||
| 217 | // verify compression format | ||
| 218 | if( CFSwapInt16BigToHost(header->compression_type) != CCZ_COMPRESSION_ZLIB ) { | ||
| 219 | CCLOG(@"cocos2d: CCZ Unsupported compression method"); | ||
| 220 | free(compressed); | ||
| 221 | return -1; | ||
| 222 | } | ||
| 223 | |||
| 224 | uint32_t len = CFSwapInt32BigToHost( header->len ); | ||
| 225 | |||
| 226 | *out = malloc( len ); | ||
| 227 | if(! *out ) | ||
| 228 | { | ||
| 229 | CCLOG(@"cocos2d: CCZ: Failed to allocate memory for texture"); | ||
| 230 | free(compressed); | ||
| 231 | return -1; | ||
| 232 | } | ||
| 233 | |||
| 234 | |||
| 235 | uLongf destlen = len; | ||
| 236 | uLongf source = (uLongf) compressed + sizeof(*header); | ||
| 237 | int ret = uncompress(*out, &destlen, (Bytef*)source, fileLen - sizeof(*header) ); | ||
| 238 | |||
| 239 | free( compressed ); | ||
| 240 | |||
| 241 | if( ret != Z_OK ) | ||
| 242 | { | ||
| 243 | CCLOG(@"cocos2d: CCZ: Failed to uncompress data"); | ||
| 244 | free( *out ); | ||
| 245 | *out = NULL; | ||
| 246 | return -1; | ||
| 247 | } | ||
| 248 | |||
| 249 | |||
| 250 | return len; | ||
| 251 | } | ||
| diff --git a/libs/cocos2d/Support/base64.c b/libs/cocos2d/Support/base64.c new file mode 100755 index 0000000..9aa52a6 --- /dev/null +++ b/libs/cocos2d/Support/base64.c | |||
| @@ -0,0 +1,93 @@ | |||
| 1 | /* | ||
| 2 | public domain BASE64 code | ||
| 3 | |||
| 4 | modified for cocos2d-iphone: http://www.cocos2d-iphone.org | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <stdio.h> | ||
| 8 | #include <stdlib.h> | ||
| 9 | |||
| 10 | #include "base64.h" | ||
| 11 | |||
| 12 | unsigned char alphabet[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
| 13 | |||
| 14 | int _base64Decode( unsigned char *input, unsigned int input_len, unsigned char *output, unsigned int *output_len ); | ||
| 15 | |||
| 16 | int _base64Decode( unsigned char *input, unsigned int input_len, unsigned char *output, unsigned int *output_len ) | ||
| 17 | { | ||
| 18 | static char inalphabet[256], decoder[256]; | ||
| 19 | int i, bits, c, char_count, errors = 0; | ||
| 20 | unsigned int input_idx = 0; | ||
| 21 | unsigned int output_idx = 0; | ||
| 22 | |||
| 23 | for (i = (sizeof alphabet) - 1; i >= 0 ; i--) { | ||
| 24 | inalphabet[alphabet[i]] = 1; | ||
| 25 | decoder[alphabet[i]] = i; | ||
| 26 | } | ||
| 27 | |||
| 28 | char_count = 0; | ||
| 29 | bits = 0; | ||
| 30 | for( input_idx=0; input_idx < input_len ; input_idx++ ) { | ||
| 31 | c = input[ input_idx ]; | ||
| 32 | if (c == '=') | ||
| 33 | break; | ||
| 34 | if (c > 255 || ! inalphabet[c]) | ||
| 35 | continue; | ||
| 36 | bits += decoder[c]; | ||
| 37 | char_count++; | ||
| 38 | if (char_count == 4) { | ||
| 39 | output[ output_idx++ ] = (bits >> 16); | ||
| 40 | output[ output_idx++ ] = ((bits >> 8) & 0xff); | ||
| 41 | output[ output_idx++ ] = ( bits & 0xff); | ||
| 42 | bits = 0; | ||
| 43 | char_count = 0; | ||
| 44 | } else { | ||
| 45 | bits <<= 6; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | if( c == '=' ) { | ||
| 50 | switch (char_count) { | ||
| 51 | case 1: | ||
| 52 | fprintf(stderr, "base64Decode: encoding incomplete: at least 2 bits missing"); | ||
| 53 | errors++; | ||
| 54 | break; | ||
| 55 | case 2: | ||
| 56 | output[ output_idx++ ] = ( bits >> 10 ); | ||
| 57 | break; | ||
| 58 | case 3: | ||
| 59 | output[ output_idx++ ] = ( bits >> 16 ); | ||
| 60 | output[ output_idx++ ] = (( bits >> 8 ) & 0xff); | ||
| 61 | break; | ||
| 62 | } | ||
| 63 | } else if ( input_idx < input_len ) { | ||
| 64 | if (char_count) { | ||
| 65 | fprintf(stderr, "base64 encoding incomplete: at least %d bits truncated", | ||
| 66 | ((4 - char_count) * 6)); | ||
| 67 | errors++; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | *output_len = output_idx; | ||
| 72 | return errors; | ||
| 73 | } | ||
| 74 | |||
| 75 | int base64Decode(unsigned char *in, unsigned int inLength, unsigned char **out) | ||
| 76 | { | ||
| 77 | unsigned int outLength = 0; | ||
| 78 | |||
| 79 | //should be enough to store 6-bit buffers in 8-bit buffers | ||
| 80 | *out = malloc( inLength * 3.0f / 4.0f + 1 ); | ||
| 81 | if( *out ) { | ||
| 82 | int ret = _base64Decode(in, inLength, *out, &outLength); | ||
| 83 | |||
| 84 | if (ret > 0 ) | ||
| 85 | { | ||
| 86 | printf("Base64Utils: error decoding"); | ||
| 87 | free(*out); | ||
| 88 | *out = NULL; | ||
| 89 | outLength = 0; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | return outLength; | ||
| 93 | } | ||
| diff --git a/libs/cocos2d/Support/base64.h b/libs/cocos2d/Support/base64.h new file mode 100755 index 0000000..d30878e --- /dev/null +++ b/libs/cocos2d/Support/base64.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | /* | ||
| 2 | public domain BASE64 code | ||
| 3 | |||
| 4 | modified for cocos2d-iphone: http://www.cocos2d-iphone.org | ||
| 5 | */ | ||
| 6 | |||
| 7 | #ifndef __CC_BASE64_DECODE_H | ||
| 8 | #define __CC_BASE64_DECODE_H | ||
| 9 | |||
| 10 | #ifdef __cplusplus | ||
| 11 | extern "C" { | ||
| 12 | #endif | ||
| 13 | |||
| 14 | |||
| 15 | /** @file | ||
| 16 | base64 helper functions | ||
| 17 | */ | ||
| 18 | |||
| 19 | /** | ||
| 20 | * Decodes a 64base encoded memory. The decoded memory is | ||
| 21 | * expected to be freed by the caller. | ||
| 22 | * | ||
| 23 | * @returns the length of the out buffer | ||
| 24 | * | ||
| 25 | @since v0.8.1 | ||
| 26 | */ | ||
| 27 | int base64Decode(unsigned char *in, unsigned int inLength, unsigned char **out); | ||
| 28 | |||
| 29 | #ifdef __cplusplus | ||
| 30 | } | ||
| 31 | #endif | ||
| 32 | |||
| 33 | #endif // __CC_BASE64_DECODE_H | ||
| diff --git a/libs/cocos2d/Support/ccCArray.h b/libs/cocos2d/Support/ccCArray.h new file mode 100755 index 0000000..20d9633 --- /dev/null +++ b/libs/cocos2d/Support/ccCArray.h | |||
| @@ -0,0 +1,447 @@ | |||
| 1 | /* Copyright (c) 2007 Scott Lembcke | ||
| 2 | * | ||
| 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 4 | * of this software and associated documentation files (the "Software"), to deal | ||
| 5 | * in the Software without restriction, including without limitation the rights | ||
| 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 7 | * copies of the Software, and to permit persons to whom the Software is | ||
| 8 | * furnished to do so, subject to the following conditions: | ||
| 9 | * | ||
| 10 | * The above copyright notice and this permission notice shall be included in | ||
| 11 | * all copies or substantial portions of the Software. | ||
| 12 | * | ||
| 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 19 | * SOFTWARE. | ||
| 20 | */ | ||
| 21 | |||
| 22 | /** | ||
| 23 | @file | ||
| 24 | Based on Chipmunk cpArray. | ||
| 25 | ccArray is a faster alternative to NSMutableArray, it does pretty much the | ||
| 26 | same thing (stores NSObjects and retains/releases them appropriately). It's | ||
| 27 | faster because: | ||
| 28 | - it uses a plain C interface so it doesn't incur Objective-c messaging overhead | ||
| 29 | - it assumes you know what you're doing, so it doesn't spend time on safety checks | ||
| 30 | (index out of bounds, required capacity etc.) | ||
| 31 | - comparisons are done using pointer equality instead of isEqual | ||
| 32 | |||
| 33 | There are 2 kind of functions: | ||
| 34 | - ccArray functions that manipulates objective-c objects (retain and release are performanced) | ||
| 35 | - ccCArray functions that manipulates values like if they were standard C structures (no retain/release is performed) | ||
| 36 | */ | ||
| 37 | |||
| 38 | #ifndef CC_ARRAY_H | ||
| 39 | #define CC_ARRAY_H | ||
| 40 | |||
| 41 | #import <Foundation/Foundation.h> | ||
| 42 | |||
| 43 | #import <stdlib.h> | ||
| 44 | #import <string.h> | ||
| 45 | |||
| 46 | |||
| 47 | #pragma mark - | ||
| 48 | #pragma mark ccArray for Objects | ||
| 49 | |||
| 50 | // Easy integration | ||
| 51 | #define CCARRAYDATA_FOREACH(__array__, __object__) \ | ||
| 52 | __object__=__array__->arr[0]; for(NSUInteger i=0, num=__array__->num; i<num; i++, __object__=__array__->arr[i]) \ | ||
| 53 | |||
| 54 | |||
| 55 | typedef struct ccArray { | ||
| 56 | NSUInteger num, max; | ||
| 57 | id *arr; | ||
| 58 | } ccArray; | ||
| 59 | |||
| 60 | /** Allocates and initializes a new array with specified capacity */ | ||
| 61 | static inline ccArray* ccArrayNew(NSUInteger capacity) { | ||
| 62 | if (capacity == 0) | ||
| 63 | capacity = 1; | ||
| 64 | |||
| 65 | ccArray *arr = (ccArray*)malloc( sizeof(ccArray) ); | ||
| 66 | arr->num = 0; | ||
| 67 | arr->arr = (id*) malloc( capacity * sizeof(id) ); | ||
| 68 | arr->max = capacity; | ||
| 69 | |||
| 70 | return arr; | ||
| 71 | } | ||
| 72 | |||
| 73 | static inline void ccArrayRemoveAllObjects(ccArray *arr); | ||
| 74 | |||
| 75 | /** Frees array after removing all remaining objects. Silently ignores nil arr. */ | ||
| 76 | static inline void ccArrayFree(ccArray *arr) | ||
| 77 | { | ||
| 78 | if( arr == nil ) return; | ||
| 79 | |||
| 80 | ccArrayRemoveAllObjects(arr); | ||
| 81 | |||
| 82 | free(arr->arr); | ||
| 83 | free(arr); | ||
| 84 | } | ||
| 85 | |||
| 86 | /** Doubles array capacity */ | ||
| 87 | static inline void ccArrayDoubleCapacity(ccArray *arr) | ||
| 88 | { | ||
| 89 | arr->max *= 2; | ||
| 90 | id *newArr = (id *)realloc( arr->arr, arr->max * sizeof(id) ); | ||
| 91 | // will fail when there's not enough memory | ||
| 92 | NSCAssert(newArr != NULL, @"ccArrayDoubleCapacity failed. Not enough memory"); | ||
| 93 | arr->arr = newArr; | ||
| 94 | } | ||
| 95 | |||
| 96 | /** Increases array capacity such that max >= num + extra. */ | ||
| 97 | static inline void ccArrayEnsureExtraCapacity(ccArray *arr, NSUInteger extra) | ||
| 98 | { | ||
| 99 | while (arr->max < arr->num + extra) | ||
| 100 | ccArrayDoubleCapacity(arr); | ||
| 101 | } | ||
| 102 | |||
| 103 | /** shrinks the array so the memory footprint corresponds with the number of items */ | ||
| 104 | static inline void ccArrayShrink(ccArray *arr) | ||
| 105 | { | ||
| 106 | NSUInteger newSize; | ||
| 107 | |||
| 108 | //only resize when necessary | ||
| 109 | if (arr->max > arr->num && !(arr->num==0 && arr->max==1)) | ||
| 110 | { | ||
| 111 | if (arr->num!=0) | ||
| 112 | { | ||
| 113 | newSize=arr->num; | ||
| 114 | arr->max=arr->num; | ||
| 115 | } | ||
| 116 | else | ||
| 117 | {//minimum capacity of 1, with 0 elements the array would be free'd by realloc | ||
| 118 | newSize=1; | ||
| 119 | arr->max=1; | ||
| 120 | } | ||
| 121 | |||
| 122 | arr->arr = (id*) realloc(arr->arr,newSize * sizeof(id) ); | ||
| 123 | NSCAssert(arr->arr!=NULL,@"could not reallocate the memory"); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | /** Returns index of first occurence of object, NSNotFound if object not found. */ | ||
| 128 | static inline NSUInteger ccArrayGetIndexOfObject(ccArray *arr, id object) | ||
| 129 | { | ||
| 130 | for( NSUInteger i = 0; i < arr->num; i++) | ||
| 131 | if( arr->arr[i] == object ) return i; | ||
| 132 | |||
| 133 | return NSNotFound; | ||
| 134 | } | ||
| 135 | |||
| 136 | /** Returns a Boolean value that indicates whether object is present in array. */ | ||
| 137 | static inline BOOL ccArrayContainsObject(ccArray *arr, id object) | ||
| 138 | { | ||
| 139 | return ccArrayGetIndexOfObject(arr, object) != NSNotFound; | ||
| 140 | } | ||
| 141 | |||
| 142 | /** Appends an object. Bahaviour undefined if array doesn't have enough capacity. */ | ||
| 143 | static inline void ccArrayAppendObject(ccArray *arr, id object) | ||
| 144 | { | ||
| 145 | arr->arr[arr->num] = [object retain]; | ||
| 146 | arr->num++; | ||
| 147 | } | ||
| 148 | |||
| 149 | /** Appends an object. Capacity of arr is increased if needed. */ | ||
| 150 | static inline void ccArrayAppendObjectWithResize(ccArray *arr, id object) | ||
| 151 | { | ||
| 152 | ccArrayEnsureExtraCapacity(arr, 1); | ||
| 153 | ccArrayAppendObject(arr, object); | ||
| 154 | } | ||
| 155 | |||
| 156 | /** Appends objects from plusArr to arr. Behaviour undefined if arr doesn't have | ||
| 157 | enough capacity. */ | ||
| 158 | static inline void ccArrayAppendArray(ccArray *arr, ccArray *plusArr) | ||
| 159 | { | ||
| 160 | for( NSUInteger i = 0; i < plusArr->num; i++) | ||
| 161 | ccArrayAppendObject(arr, plusArr->arr[i]); | ||
| 162 | } | ||
| 163 | |||
| 164 | /** Appends objects from plusArr to arr. Capacity of arr is increased if needed. */ | ||
| 165 | static inline void ccArrayAppendArrayWithResize(ccArray *arr, ccArray *plusArr) | ||
| 166 | { | ||
| 167 | ccArrayEnsureExtraCapacity(arr, plusArr->num); | ||
| 168 | ccArrayAppendArray(arr, plusArr); | ||
| 169 | } | ||
| 170 | |||
| 171 | /** Inserts an object at index */ | ||
| 172 | static inline void ccArrayInsertObjectAtIndex(ccArray *arr, id object, NSUInteger index) | ||
| 173 | { | ||
| 174 | NSCAssert(index<=arr->num, @"Invalid index. Out of bounds"); | ||
| 175 | |||
| 176 | ccArrayEnsureExtraCapacity(arr, 1); | ||
| 177 | |||
| 178 | NSUInteger remaining = arr->num - index; | ||
| 179 | if( remaining > 0) | ||
| 180 | memmove(&arr->arr[index+1], &arr->arr[index], sizeof(id) * remaining ); | ||
| 181 | |||
| 182 | arr->arr[index] = [object retain]; | ||
| 183 | arr->num++; | ||
| 184 | } | ||
| 185 | |||
| 186 | /** Swaps two objects */ | ||
| 187 | static inline void ccArraySwapObjectsAtIndexes(ccArray *arr, NSUInteger index1, NSUInteger index2) | ||
| 188 | { | ||
| 189 | NSCAssert(index1 < arr->num, @"(1) Invalid index. Out of bounds"); | ||
| 190 | NSCAssert(index2 < arr->num, @"(2) Invalid index. Out of bounds"); | ||
| 191 | |||
| 192 | id object1 = arr->arr[index1]; | ||
| 193 | |||
| 194 | arr->arr[index1] = arr->arr[index2]; | ||
| 195 | arr->arr[index2] = object1; | ||
| 196 | } | ||
| 197 | |||
| 198 | /** Removes all objects from arr */ | ||
| 199 | static inline void ccArrayRemoveAllObjects(ccArray *arr) | ||
| 200 | { | ||
| 201 | while( arr->num > 0 ) | ||
| 202 | [arr->arr[--arr->num] release]; | ||
| 203 | } | ||
| 204 | |||
| 205 | /** Removes object at specified index and pushes back all subsequent objects. | ||
| 206 | Behaviour undefined if index outside [0, num-1]. */ | ||
| 207 | static inline void ccArrayRemoveObjectAtIndex(ccArray *arr, NSUInteger index) | ||
| 208 | { | ||
| 209 | [arr->arr[index] release]; | ||
| 210 | arr->num--; | ||
| 211 | |||
| 212 | NSUInteger remaining = arr->num - index; | ||
| 213 | if(remaining>0) | ||
| 214 | memmove(&arr->arr[index], &arr->arr[index+1], remaining * sizeof(id)); | ||
| 215 | } | ||
| 216 | |||
| 217 | /** Removes object at specified index and fills the gap with the last object, | ||
| 218 | thereby avoiding the need to push back subsequent objects. | ||
| 219 | Behaviour undefined if index outside [0, num-1]. */ | ||
| 220 | static inline void ccArrayFastRemoveObjectAtIndex(ccArray *arr, NSUInteger index) | ||
| 221 | { | ||
| 222 | [arr->arr[index] release]; | ||
| 223 | NSUInteger last = --arr->num; | ||
| 224 | arr->arr[index] = arr->arr[last]; | ||
| 225 | } | ||
| 226 | |||
| 227 | static inline void ccArrayFastRemoveObject(ccArray *arr, id object) | ||
| 228 | { | ||
| 229 | NSUInteger index = ccArrayGetIndexOfObject(arr, object); | ||
| 230 | if (index != NSNotFound) | ||
| 231 | ccArrayFastRemoveObjectAtIndex(arr, index); | ||
| 232 | } | ||
| 233 | |||
| 234 | /** Searches for the first occurance of object and removes it. If object is not | ||
| 235 | found the function has no effect. */ | ||
| 236 | static inline void ccArrayRemoveObject(ccArray *arr, id object) | ||
| 237 | { | ||
| 238 | NSUInteger index = ccArrayGetIndexOfObject(arr, object); | ||
| 239 | if (index != NSNotFound) | ||
| 240 | ccArrayRemoveObjectAtIndex(arr, index); | ||
| 241 | } | ||
| 242 | |||
| 243 | /** Removes from arr all objects in minusArr. For each object in minusArr, the | ||
| 244 | first matching instance in arr will be removed. */ | ||
| 245 | static inline void ccArrayRemoveArray(ccArray *arr, ccArray *minusArr) | ||
| 246 | { | ||
| 247 | for( NSUInteger i = 0; i < minusArr->num; i++) | ||
| 248 | ccArrayRemoveObject(arr, minusArr->arr[i]); | ||
| 249 | } | ||
| 250 | |||
| 251 | /** Removes from arr all objects in minusArr. For each object in minusArr, all | ||
| 252 | matching instances in arr will be removed. */ | ||
| 253 | static inline void ccArrayFullRemoveArray(ccArray *arr, ccArray *minusArr) | ||
| 254 | { | ||
| 255 | NSUInteger back = 0; | ||
| 256 | |||
| 257 | for( NSUInteger i = 0; i < arr->num; i++) { | ||
| 258 | if( ccArrayContainsObject(minusArr, arr->arr[i]) ) { | ||
| 259 | [arr->arr[i] release]; | ||
| 260 | back++; | ||
| 261 | } else | ||
| 262 | arr->arr[i - back] = arr->arr[i]; | ||
| 263 | } | ||
| 264 | |||
| 265 | arr->num -= back; | ||
| 266 | } | ||
| 267 | |||
| 268 | /** Sends to each object in arr the message identified by given selector. */ | ||
| 269 | static inline void ccArrayMakeObjectsPerformSelector(ccArray *arr, SEL sel) | ||
| 270 | { | ||
| 271 | for( NSUInteger i = 0; i < arr->num; i++) | ||
| 272 | [arr->arr[i] performSelector:sel]; | ||
| 273 | } | ||
| 274 | |||
| 275 | static inline void ccArrayMakeObjectsPerformSelectorWithObject(ccArray *arr, SEL sel, id object) | ||
| 276 | { | ||
| 277 | for( NSUInteger i = 0; i < arr->num; i++) | ||
| 278 | [arr->arr[i] performSelector:sel withObject:object]; | ||
| 279 | } | ||
| 280 | |||
| 281 | |||
| 282 | #pragma mark - | ||
| 283 | #pragma mark ccCArray for Values (c structures) | ||
| 284 | |||
| 285 | typedef ccArray ccCArray; | ||
| 286 | |||
| 287 | static inline void ccCArrayRemoveAllValues(ccCArray *arr); | ||
| 288 | |||
| 289 | /** Allocates and initializes a new C array with specified capacity */ | ||
| 290 | static inline ccCArray* ccCArrayNew(NSUInteger capacity) { | ||
| 291 | if (capacity == 0) | ||
| 292 | capacity = 1; | ||
| 293 | |||
| 294 | ccCArray *arr = (ccCArray*)malloc( sizeof(ccCArray) ); | ||
| 295 | arr->num = 0; | ||
| 296 | arr->arr = (id*) malloc( capacity * sizeof(id) ); | ||
| 297 | arr->max = capacity; | ||
| 298 | |||
| 299 | return arr; | ||
| 300 | } | ||
| 301 | |||
| 302 | /** Frees C array after removing all remaining values. Silently ignores nil arr. */ | ||
| 303 | static inline void ccCArrayFree(ccCArray *arr) | ||
| 304 | { | ||
| 305 | if( arr == nil ) return; | ||
| 306 | |||
| 307 | ccCArrayRemoveAllValues(arr); | ||
| 308 | |||
| 309 | free(arr->arr); | ||
| 310 | free(arr); | ||
| 311 | } | ||
| 312 | |||
| 313 | /** Doubles C array capacity */ | ||
| 314 | static inline void ccCArrayDoubleCapacity(ccCArray *arr) | ||
| 315 | { | ||
| 316 | ccArrayDoubleCapacity(arr); | ||
| 317 | } | ||
| 318 | |||
| 319 | /** Increases array capacity such that max >= num + extra. */ | ||
| 320 | static inline void ccCArrayEnsureExtraCapacity(ccCArray *arr, NSUInteger extra) | ||
| 321 | { | ||
| 322 | ccArrayEnsureExtraCapacity(arr,extra); | ||
| 323 | } | ||
| 324 | |||
| 325 | /** Returns index of first occurence of value, NSNotFound if value not found. */ | ||
| 326 | static inline NSUInteger ccCArrayGetIndexOfValue(ccCArray *arr, void* value) | ||
| 327 | { | ||
| 328 | for( NSUInteger i = 0; i < arr->num; i++) | ||
| 329 | if( arr->arr[i] == value ) return i; | ||
| 330 | return NSNotFound; | ||
| 331 | } | ||
| 332 | |||
| 333 | /** Returns a Boolean value that indicates whether value is present in the C array. */ | ||
| 334 | static inline BOOL ccCArrayContainsValue(ccCArray *arr, void* value) | ||
| 335 | { | ||
| 336 | return ccCArrayGetIndexOfValue(arr, value) != NSNotFound; | ||
| 337 | } | ||
| 338 | |||
| 339 | /** Inserts a value at a certain position. Behaviour undefined if aray doesn't have enough capacity */ | ||
| 340 | static inline void ccCArrayInsertValueAtIndex( ccCArray *arr, void *value, NSUInteger index) | ||
| 341 | { | ||
| 342 | NSCAssert( index < arr->max, @"ccCArrayInsertValueAtIndex: invalid index"); | ||
| 343 | |||
| 344 | NSUInteger remaining = arr->num - index; | ||
| 345 | |||
| 346 | // last Value doesn't need to be moved | ||
| 347 | if( remaining > 0) { | ||
| 348 | // tex coordinates | ||
| 349 | memmove( &arr->arr[index+1],&arr->arr[index], sizeof(void*) * remaining ); | ||
| 350 | } | ||
| 351 | |||
| 352 | arr->num++; | ||
| 353 | arr->arr[index] = (id) value; | ||
| 354 | } | ||
| 355 | |||
| 356 | /** Appends an value. Bahaviour undefined if array doesn't have enough capacity. */ | ||
| 357 | static inline void ccCArrayAppendValue(ccCArray *arr, void* value) | ||
| 358 | { | ||
| 359 | arr->arr[arr->num] = (id) value; | ||
| 360 | arr->num++; | ||
| 361 | } | ||
| 362 | |||
| 363 | /** Appends an value. Capacity of arr is increased if needed. */ | ||
| 364 | static inline void ccCArrayAppendValueWithResize(ccCArray *arr, void* value) | ||
| 365 | { | ||
| 366 | ccCArrayEnsureExtraCapacity(arr, 1); | ||
| 367 | ccCArrayAppendValue(arr, value); | ||
| 368 | } | ||
| 369 | |||
| 370 | /** Appends values from plusArr to arr. Behaviour undefined if arr doesn't have | ||
| 371 | enough capacity. */ | ||
| 372 | static inline void ccCArrayAppendArray(ccCArray *arr, ccCArray *plusArr) | ||
| 373 | { | ||
| 374 | for( NSUInteger i = 0; i < plusArr->num; i++) | ||
| 375 | ccCArrayAppendValue(arr, plusArr->arr[i]); | ||
| 376 | } | ||
| 377 | |||
| 378 | /** Appends values from plusArr to arr. Capacity of arr is increased if needed. */ | ||
| 379 | static inline void ccCArrayAppendArrayWithResize(ccCArray *arr, ccCArray *plusArr) | ||
| 380 | { | ||
| 381 | ccCArrayEnsureExtraCapacity(arr, plusArr->num); | ||
| 382 | ccCArrayAppendArray(arr, plusArr); | ||
| 383 | } | ||
| 384 | |||
| 385 | /** Removes all values from arr */ | ||
| 386 | static inline void ccCArrayRemoveAllValues(ccCArray *arr) | ||
| 387 | { | ||
| 388 | arr->num = 0; | ||
| 389 | } | ||
| 390 | |||
| 391 | /** Removes value at specified index and pushes back all subsequent values. | ||
| 392 | Behaviour undefined if index outside [0, num-1]. | ||
| 393 | @since v0.99.4 | ||
| 394 | */ | ||
| 395 | static inline void ccCArrayRemoveValueAtIndex(ccCArray *arr, NSUInteger index) | ||
| 396 | { | ||
| 397 | for( NSUInteger last = --arr->num; index < last; index++) | ||
| 398 | arr->arr[index] = arr->arr[index + 1]; | ||
| 399 | } | ||
| 400 | |||
| 401 | /** Removes value at specified index and fills the gap with the last value, | ||
| 402 | thereby avoiding the need to push back subsequent values. | ||
| 403 | Behaviour undefined if index outside [0, num-1]. | ||
| 404 | @since v0.99.4 | ||
| 405 | */ | ||
| 406 | static inline void ccCArrayFastRemoveValueAtIndex(ccCArray *arr, NSUInteger index) | ||
| 407 | { | ||
| 408 | NSUInteger last = --arr->num; | ||
| 409 | arr->arr[index] = arr->arr[last]; | ||
| 410 | } | ||
| 411 | |||
| 412 | /** Searches for the first occurance of value and removes it. If value is not found the function has no effect. | ||
| 413 | @since v0.99.4 | ||
| 414 | */ | ||
| 415 | static inline void ccCArrayRemoveValue(ccCArray *arr, void* value) | ||
| 416 | { | ||
| 417 | NSUInteger index = ccCArrayGetIndexOfValue(arr, value); | ||
| 418 | if (index != NSNotFound) | ||
| 419 | ccCArrayRemoveValueAtIndex(arr, index); | ||
| 420 | } | ||
| 421 | |||
| 422 | /** Removes from arr all values in minusArr. For each Value in minusArr, the first matching instance in arr will be removed. | ||
| 423 | @since v0.99.4 | ||
| 424 | */ | ||
| 425 | static inline void ccCArrayRemoveArray(ccCArray *arr, ccCArray *minusArr) | ||
| 426 | { | ||
| 427 | for( NSUInteger i = 0; i < minusArr->num; i++) | ||
| 428 | ccCArrayRemoveValue(arr, minusArr->arr[i]); | ||
| 429 | } | ||
| 430 | |||
| 431 | /** Removes from arr all values in minusArr. For each value in minusArr, all matching instances in arr will be removed. | ||
| 432 | @since v0.99.4 | ||
| 433 | */ | ||
| 434 | static inline void ccCArrayFullRemoveArray(ccCArray *arr, ccCArray *minusArr) | ||
| 435 | { | ||
| 436 | NSUInteger back = 0; | ||
| 437 | |||
| 438 | for( NSUInteger i = 0; i < arr->num; i++) { | ||
| 439 | if( ccCArrayContainsValue(minusArr, arr->arr[i]) ) { | ||
| 440 | back++; | ||
| 441 | } else | ||
| 442 | arr->arr[i - back] = arr->arr[i]; | ||
| 443 | } | ||
| 444 | |||
| 445 | arr->num -= back; | ||
| 446 | } | ||
| 447 | #endif // CC_ARRAY_H | ||
| diff --git a/libs/cocos2d/Support/ccUtils.c b/libs/cocos2d/Support/ccUtils.c new file mode 100755 index 0000000..39786ec --- /dev/null +++ b/libs/cocos2d/Support/ccUtils.c | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | /* | ||
| 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | */ | ||
| 5 | |||
| 6 | /* | ||
| 7 | ccNextPOT function is licensed under the same license that is used in CCTexture2D.m. | ||
| 8 | */ | ||
| 9 | #include "ccUtils.h" | ||
| 10 | |||
| 11 | unsigned long ccNextPOT(unsigned long x) | ||
| 12 | { | ||
| 13 | x = x - 1; | ||
| 14 | x = x | (x >> 1); | ||
| 15 | x = x | (x >> 2); | ||
| 16 | x = x | (x >> 4); | ||
| 17 | x = x | (x >> 8); | ||
| 18 | x = x | (x >>16); | ||
| 19 | return x + 1; | ||
| 20 | } \ No newline at end of file | ||
| diff --git a/libs/cocos2d/Support/ccUtils.h b/libs/cocos2d/Support/ccUtils.h new file mode 100755 index 0000000..783fc54 --- /dev/null +++ b/libs/cocos2d/Support/ccUtils.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | /* | ||
| 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef __CC_UTILS_H | ||
| 7 | #define __CC_UTILS_H | ||
| 8 | |||
| 9 | /** @file ccUtils.h | ||
| 10 | Misc free functions | ||
| 11 | */ | ||
| 12 | |||
| 13 | /* | ||
| 14 | ccNextPOT function is licensed under the same license that is used in CCTexture2D.m. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /** returns the Next Power of Two value. | ||
| 18 | |||
| 19 | Examples: | ||
| 20 | - If "value" is 15, it will return 16. | ||
| 21 | - If "value" is 16, it will return 16. | ||
| 22 | - If "value" is 17, it will return 32. | ||
| 23 | |||
| 24 | @since v0.99.5 | ||
| 25 | */ | ||
| 26 | |||
| 27 | unsigned long ccNextPOT( unsigned long value ); | ||
| 28 | |||
| 29 | #endif // ! __CC_UTILS_H | ||
| diff --git a/libs/cocos2d/Support/uthash.h b/libs/cocos2d/Support/uthash.h new file mode 100755 index 0000000..a4bdc18 --- /dev/null +++ b/libs/cocos2d/Support/uthash.h | |||
| @@ -0,0 +1,972 @@ | |||
| 1 | /* | ||
| 2 | Copyright (c) 2003-2010, Troy D. Hanson http://uthash.sourceforge.net | ||
| 3 | All rights reserved. | ||
| 4 | |||
| 5 | Redistribution and use in source and binary forms, with or without | ||
| 6 | modification, are permitted provided that the following conditions are met: | ||
| 7 | |||
| 8 | * Redistributions of source code must retain the above copyright | ||
| 9 | notice, this list of conditions and the following disclaimer. | ||
| 10 | |||
| 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | ||
| 12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||
| 13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | ||
| 14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | ||
| 15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
| 16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
| 17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
| 18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
| 19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
| 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #ifndef UTHASH_H | ||
| 25 | #define UTHASH_H | ||
| 26 | |||
| 27 | #include <string.h> /* memcmp,strlen */ | ||
| 28 | #include <stddef.h> /* ptrdiff_t */ | ||
| 29 | |||
| 30 | /* These macros use decltype or the earlier __typeof GNU extension. | ||
| 31 | As decltype is only available in newer compilers (VS2010 or gcc 4.3+ | ||
| 32 | when compiling c++ source) this code uses whatever method is needed | ||
| 33 | or, for VS2008 where neither is available, uses casting workarounds. */ | ||
| 34 | #ifdef _MSC_VER /* MS compiler */ | ||
| 35 | #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ | ||
| 36 | #define DECLTYPE(x) (decltype(x)) | ||
| 37 | #else /* VS2008 or older (or VS2010 in C mode) */ | ||
| 38 | #define NO_DECLTYPE | ||
| 39 | #define DECLTYPE(x) | ||
| 40 | #endif | ||
| 41 | #else /* GNU, Sun and other compilers */ | ||
| 42 | #define DECLTYPE(x) (__typeof(x)) | ||
| 43 | #endif | ||
| 44 | |||
| 45 | #ifdef NO_DECLTYPE | ||
| 46 | #define DECLTYPE_ASSIGN(dst,src) \ | ||
| 47 | do { \ | ||
| 48 | char **_da_dst = (char**)(&(dst)); \ | ||
| 49 | *_da_dst = (char*)(src); \ | ||
| 50 | } while(0) | ||
| 51 | #else | ||
| 52 | #define DECLTYPE_ASSIGN(dst,src) \ | ||
| 53 | do { \ | ||
| 54 | (dst) = DECLTYPE(dst)(src); \ | ||
| 55 | } while(0) | ||
| 56 | #endif | ||
| 57 | |||
| 58 | /* a number of the hash function use uint32_t which isn't defined on win32 */ | ||
| 59 | #ifdef _MSC_VER | ||
| 60 | typedef unsigned int uint32_t; | ||
| 61 | #else | ||
| 62 | #include <inttypes.h> /* uint32_t */ | ||
| 63 | #endif | ||
| 64 | |||
| 65 | #define UTHASH_VERSION 1.9.3 | ||
| 66 | |||
| 67 | #define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ | ||
| 68 | #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ | ||
| 69 | #define uthash_free(ptr,sz) free(ptr) /* free fcn */ | ||
| 70 | |||
| 71 | #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ | ||
| 72 | #define uthash_expand_fyi(tbl) /* can be defined to log expands */ | ||
| 73 | |||
| 74 | /* initial number of buckets */ | ||
| 75 | #define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ | ||
| 76 | #define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ | ||
| 77 | #define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ | ||
| 78 | |||
| 79 | /* calculate the element whose hash handle address is hhe */ | ||
| 80 | #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) | ||
| 81 | |||
| 82 | #define HASH_FIND(hh,head,keyptr,keylen,out) \ | ||
| 83 | do { \ | ||
| 84 | unsigned _hf_bkt,_hf_hashv; \ | ||
| 85 | out=NULL; \ | ||
| 86 | if (head) { \ | ||
| 87 | HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ | ||
| 88 | if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ | ||
| 89 | HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ | ||
| 90 | keyptr,keylen,out); \ | ||
| 91 | } \ | ||
| 92 | } \ | ||
| 93 | } while (0) | ||
| 94 | |||
| 95 | #ifdef HASH_BLOOM | ||
| 96 | #define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) | ||
| 97 | #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) | ||
| 98 | #define HASH_BLOOM_MAKE(tbl) \ | ||
| 99 | do { \ | ||
| 100 | (tbl)->bloom_nbits = HASH_BLOOM; \ | ||
| 101 | (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ | ||
| 102 | if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ | ||
| 103 | memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ | ||
| 104 | (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ | ||
| 105 | } while (0); | ||
| 106 | |||
| 107 | #define HASH_BLOOM_FREE(tbl) \ | ||
| 108 | do { \ | ||
| 109 | uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ | ||
| 110 | } while (0); | ||
| 111 | |||
| 112 | #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) | ||
| 113 | #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) | ||
| 114 | |||
| 115 | #define HASH_BLOOM_ADD(tbl,hashv) \ | ||
| 116 | HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) | ||
| 117 | |||
| 118 | #define HASH_BLOOM_TEST(tbl,hashv) \ | ||
| 119 | HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) | ||
| 120 | |||
| 121 | #else | ||
| 122 | #define HASH_BLOOM_MAKE(tbl) | ||
| 123 | #define HASH_BLOOM_FREE(tbl) | ||
| 124 | #define HASH_BLOOM_ADD(tbl,hashv) | ||
| 125 | #define HASH_BLOOM_TEST(tbl,hashv) (1) | ||
| 126 | #endif | ||
| 127 | |||
| 128 | #define HASH_MAKE_TABLE(hh,head) \ | ||
| 129 | do { \ | ||
| 130 | (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ | ||
| 131 | sizeof(UT_hash_table)); \ | ||
| 132 | if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ | ||
| 133 | memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ | ||
| 134 | (head)->hh.tbl->tail = &((head)->hh); \ | ||
| 135 | (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ | ||
| 136 | (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ | ||
| 137 | (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ | ||
| 138 | (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ | ||
| 139 | HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ | ||
| 140 | if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ | ||
| 141 | memset((head)->hh.tbl->buckets, 0, \ | ||
| 142 | HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ | ||
| 143 | HASH_BLOOM_MAKE((head)->hh.tbl); \ | ||
| 144 | (head)->hh.tbl->signature = HASH_SIGNATURE; \ | ||
| 145 | } while(0) | ||
| 146 | |||
| 147 | #define HASH_ADD(hh,head,fieldname,keylen_in,add) \ | ||
| 148 | HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add) | ||
| 149 | |||
| 150 | #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ | ||
| 151 | do { \ | ||
| 152 | unsigned _ha_bkt; \ | ||
| 153 | (add)->hh.next = NULL; \ | ||
| 154 | (add)->hh.key = (char*)keyptr; \ | ||
| 155 | (add)->hh.keylen = keylen_in; \ | ||
| 156 | if (!(head)) { \ | ||
| 157 | head = (add); \ | ||
| 158 | (head)->hh.prev = NULL; \ | ||
| 159 | HASH_MAKE_TABLE(hh,head); \ | ||
| 160 | } else { \ | ||
| 161 | (head)->hh.tbl->tail->next = (add); \ | ||
| 162 | (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ | ||
| 163 | (head)->hh.tbl->tail = &((add)->hh); \ | ||
| 164 | } \ | ||
| 165 | (head)->hh.tbl->num_items++; \ | ||
| 166 | (add)->hh.tbl = (head)->hh.tbl; \ | ||
| 167 | HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ | ||
| 168 | (add)->hh.hashv, _ha_bkt); \ | ||
| 169 | HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ | ||
| 170 | HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ | ||
| 171 | HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ | ||
| 172 | HASH_FSCK(hh,head); \ | ||
| 173 | } while(0) | ||
| 174 | |||
| 175 | #define HASH_TO_BKT( hashv, num_bkts, bkt ) \ | ||
| 176 | do { \ | ||
| 177 | bkt = ((hashv) & ((num_bkts) - 1)); \ | ||
| 178 | } while(0) | ||
| 179 | |||
| 180 | /* delete "delptr" from the hash table. | ||
| 181 | * "the usual" patch-up process for the app-order doubly-linked-list. | ||
| 182 | * The use of _hd_hh_del below deserves special explanation. | ||
| 183 | * These used to be expressed using (delptr) but that led to a bug | ||
| 184 | * if someone used the same symbol for the head and deletee, like | ||
| 185 | * HASH_DELETE(hh,users,users); | ||
| 186 | * We want that to work, but by changing the head (users) below | ||
| 187 | * we were forfeiting our ability to further refer to the deletee (users) | ||
| 188 | * in the patch-up process. Solution: use scratch space to | ||
| 189 | * copy the deletee pointer, then the latter references are via that | ||
| 190 | * scratch pointer rather than through the repointed (users) symbol. | ||
| 191 | */ | ||
| 192 | #define HASH_DELETE(hh,head,delptr) \ | ||
| 193 | do { \ | ||
| 194 | unsigned _hd_bkt; \ | ||
| 195 | struct UT_hash_handle *_hd_hh_del; \ | ||
| 196 | if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ | ||
| 197 | uthash_free((head)->hh.tbl->buckets, \ | ||
| 198 | (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ | ||
| 199 | HASH_BLOOM_FREE((head)->hh.tbl); \ | ||
| 200 | uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ | ||
| 201 | head = NULL; \ | ||
| 202 | } else { \ | ||
| 203 | _hd_hh_del = &((delptr)->hh); \ | ||
| 204 | if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ | ||
| 205 | (head)->hh.tbl->tail = \ | ||
| 206 | (UT_hash_handle*)((char*)((delptr)->hh.prev) + \ | ||
| 207 | (head)->hh.tbl->hho); \ | ||
| 208 | } \ | ||
| 209 | if ((delptr)->hh.prev) { \ | ||
| 210 | ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \ | ||
| 211 | (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ | ||
| 212 | } else { \ | ||
| 213 | DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ | ||
| 214 | } \ | ||
| 215 | if (_hd_hh_del->next) { \ | ||
| 216 | ((UT_hash_handle*)((char*)_hd_hh_del->next + \ | ||
| 217 | (head)->hh.tbl->hho))->prev = \ | ||
| 218 | _hd_hh_del->prev; \ | ||
| 219 | } \ | ||
| 220 | HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ | ||
| 221 | HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ | ||
| 222 | (head)->hh.tbl->num_items--; \ | ||
| 223 | } \ | ||
| 224 | HASH_FSCK(hh,head); \ | ||
| 225 | } while (0) | ||
| 226 | |||
| 227 | |||
| 228 | /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ | ||
| 229 | #define HASH_FIND_STR(head,findstr,out) \ | ||
| 230 | HASH_FIND(hh,head,findstr,strlen(findstr),out) | ||
| 231 | #define HASH_ADD_STR(head,strfield,add) \ | ||
| 232 | HASH_ADD(hh,head,strfield,strlen(add->strfield),add) | ||
| 233 | #define HASH_FIND_INT(head,findint,out) \ | ||
| 234 | HASH_FIND(hh,head,findint,sizeof(int),out) | ||
| 235 | #define HASH_ADD_INT(head,intfield,add) \ | ||
| 236 | HASH_ADD(hh,head,intfield,sizeof(int),add) | ||
| 237 | #define HASH_FIND_PTR(head,findptr,out) \ | ||
| 238 | HASH_FIND(hh,head,findptr,sizeof(void *),out) | ||
| 239 | #define HASH_ADD_PTR(head,ptrfield,add) \ | ||
| 240 | HASH_ADD(hh,head,ptrfield,sizeof(void *),add) | ||
| 241 | #define HASH_DEL(head,delptr) \ | ||
| 242 | HASH_DELETE(hh,head,delptr) | ||
| 243 | |||
| 244 | /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. | ||
| 245 | * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. | ||
| 246 | */ | ||
| 247 | #ifdef HASH_DEBUG | ||
| 248 | #define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) | ||
| 249 | #define HASH_FSCK(hh,head) \ | ||
| 250 | do { \ | ||
| 251 | unsigned _bkt_i; \ | ||
| 252 | unsigned _count, _bkt_count; \ | ||
| 253 | char *_prev; \ | ||
| 254 | struct UT_hash_handle *_thh; \ | ||
| 255 | if (head) { \ | ||
| 256 | _count = 0; \ | ||
| 257 | for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ | ||
| 258 | _bkt_count = 0; \ | ||
| 259 | _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ | ||
| 260 | _prev = NULL; \ | ||
| 261 | while (_thh) { \ | ||
| 262 | if (_prev != (char*)(_thh->hh_prev)) { \ | ||
| 263 | HASH_OOPS("invalid hh_prev %p, actual %p\n", \ | ||
| 264 | _thh->hh_prev, _prev ); \ | ||
| 265 | } \ | ||
| 266 | _bkt_count++; \ | ||
| 267 | _prev = (char*)(_thh); \ | ||
| 268 | _thh = _thh->hh_next; \ | ||
| 269 | } \ | ||
| 270 | _count += _bkt_count; \ | ||
| 271 | if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ | ||
| 272 | HASH_OOPS("invalid bucket count %d, actual %d\n", \ | ||
| 273 | (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ | ||
| 274 | } \ | ||
| 275 | } \ | ||
| 276 | if (_count != (head)->hh.tbl->num_items) { \ | ||
| 277 | HASH_OOPS("invalid hh item count %d, actual %d\n", \ | ||
| 278 | (head)->hh.tbl->num_items, _count ); \ | ||
| 279 | } \ | ||
| 280 | /* traverse hh in app order; check next/prev integrity, count */ \ | ||
| 281 | _count = 0; \ | ||
| 282 | _prev = NULL; \ | ||
| 283 | _thh = &(head)->hh; \ | ||
| 284 | while (_thh) { \ | ||
| 285 | _count++; \ | ||
| 286 | if (_prev !=(char*)(_thh->prev)) { \ | ||
| 287 | HASH_OOPS("invalid prev %p, actual %p\n", \ | ||
| 288 | _thh->prev, _prev ); \ | ||
| 289 | } \ | ||
| 290 | _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ | ||
| 291 | _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ | ||
| 292 | (head)->hh.tbl->hho) : NULL ); \ | ||
| 293 | } \ | ||
| 294 | if (_count != (head)->hh.tbl->num_items) { \ | ||
| 295 | HASH_OOPS("invalid app item count %d, actual %d\n", \ | ||
| 296 | (head)->hh.tbl->num_items, _count ); \ | ||
| 297 | } \ | ||
| 298 | } \ | ||
| 299 | } while (0) | ||
| 300 | #else | ||
| 301 | #define HASH_FSCK(hh,head) | ||
| 302 | #endif | ||
| 303 | |||
| 304 | /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to | ||
| 305 | * the descriptor to which this macro is defined for tuning the hash function. | ||
| 306 | * The app can #include <unistd.h> to get the prototype for write(2). */ | ||
| 307 | #ifdef HASH_EMIT_KEYS | ||
| 308 | #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ | ||
| 309 | do { \ | ||
| 310 | unsigned _klen = fieldlen; \ | ||
| 311 | write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ | ||
| 312 | write(HASH_EMIT_KEYS, keyptr, fieldlen); \ | ||
| 313 | } while (0) | ||
| 314 | #else | ||
| 315 | #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) | ||
| 316 | #endif | ||
| 317 | |||
| 318 | /* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ | ||
| 319 | #ifdef HASH_FUNCTION | ||
| 320 | #define HASH_FCN HASH_FUNCTION | ||
| 321 | #else | ||
| 322 | #define HASH_FCN HASH_JEN | ||
| 323 | #endif | ||
| 324 | |||
| 325 | /* The Bernstein hash function, used in Perl prior to v5.6 */ | ||
| 326 | #define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ | ||
| 327 | do { \ | ||
| 328 | unsigned _hb_keylen=keylen; \ | ||
| 329 | char *_hb_key=(char*)(key); \ | ||
| 330 | (hashv) = 0; \ | ||
| 331 | while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ | ||
| 332 | bkt = (hashv) & (num_bkts-1); \ | ||
| 333 | } while (0) | ||
| 334 | |||
| 335 | |||
| 336 | /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at | ||
| 337 | * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ | ||
| 338 | #define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ | ||
| 339 | do { \ | ||
| 340 | unsigned _sx_i; \ | ||
| 341 | char *_hs_key=(char*)(key); \ | ||
| 342 | hashv = 0; \ | ||
| 343 | for(_sx_i=0; _sx_i < keylen; _sx_i++) \ | ||
| 344 | hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ | ||
| 345 | bkt = hashv & (num_bkts-1); \ | ||
| 346 | } while (0) | ||
| 347 | |||
| 348 | #define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ | ||
| 349 | do { \ | ||
| 350 | unsigned _fn_i; \ | ||
| 351 | char *_hf_key=(char*)(key); \ | ||
| 352 | hashv = 2166136261UL; \ | ||
| 353 | for(_fn_i=0; _fn_i < keylen; _fn_i++) \ | ||
| 354 | hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ | ||
| 355 | bkt = hashv & (num_bkts-1); \ | ||
| 356 | } while(0); | ||
| 357 | |||
| 358 | #define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ | ||
| 359 | do { \ | ||
| 360 | unsigned _ho_i; \ | ||
| 361 | char *_ho_key=(char*)(key); \ | ||
| 362 | hashv = 0; \ | ||
| 363 | for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ | ||
| 364 | hashv += _ho_key[_ho_i]; \ | ||
| 365 | hashv += (hashv << 10); \ | ||
| 366 | hashv ^= (hashv >> 6); \ | ||
| 367 | } \ | ||
| 368 | hashv += (hashv << 3); \ | ||
| 369 | hashv ^= (hashv >> 11); \ | ||
| 370 | hashv += (hashv << 15); \ | ||
| 371 | bkt = hashv & (num_bkts-1); \ | ||
| 372 | } while(0) | ||
| 373 | |||
| 374 | #define HASH_JEN_MIX(a,b,c) \ | ||
| 375 | do { \ | ||
| 376 | a -= b; a -= c; a ^= ( c >> 13 ); \ | ||
| 377 | b -= c; b -= a; b ^= ( a << 8 ); \ | ||
| 378 | c -= a; c -= b; c ^= ( b >> 13 ); \ | ||
| 379 | a -= b; a -= c; a ^= ( c >> 12 ); \ | ||
| 380 | b -= c; b -= a; b ^= ( a << 16 ); \ | ||
| 381 | c -= a; c -= b; c ^= ( b >> 5 ); \ | ||
| 382 | a -= b; a -= c; a ^= ( c >> 3 ); \ | ||
| 383 | b -= c; b -= a; b ^= ( a << 10 ); \ | ||
| 384 | c -= a; c -= b; c ^= ( b >> 15 ); \ | ||
| 385 | } while (0) | ||
| 386 | |||
| 387 | #define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ | ||
| 388 | do { \ | ||
| 389 | unsigned _hj_i,_hj_j,_hj_k; \ | ||
| 390 | char *_hj_key=(char*)(key); \ | ||
| 391 | hashv = 0xfeedbeef; \ | ||
| 392 | _hj_i = _hj_j = 0x9e3779b9; \ | ||
| 393 | _hj_k = keylen; \ | ||
| 394 | while (_hj_k >= 12) { \ | ||
| 395 | _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ | ||
| 396 | + ( (unsigned)_hj_key[2] << 16 ) \ | ||
| 397 | + ( (unsigned)_hj_key[3] << 24 ) ); \ | ||
| 398 | _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ | ||
| 399 | + ( (unsigned)_hj_key[6] << 16 ) \ | ||
| 400 | + ( (unsigned)_hj_key[7] << 24 ) ); \ | ||
| 401 | hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ | ||
| 402 | + ( (unsigned)_hj_key[10] << 16 ) \ | ||
| 403 | + ( (unsigned)_hj_key[11] << 24 ) ); \ | ||
| 404 | \ | ||
| 405 | HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ | ||
| 406 | \ | ||
| 407 | _hj_key += 12; \ | ||
| 408 | _hj_k -= 12; \ | ||
| 409 | } \ | ||
| 410 | hashv += keylen; \ | ||
| 411 | switch ( _hj_k ) { \ | ||
| 412 | case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ | ||
| 413 | case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ | ||
| 414 | case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ | ||
| 415 | case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ | ||
| 416 | case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ | ||
| 417 | case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ | ||
| 418 | case 5: _hj_j += _hj_key[4]; \ | ||
| 419 | case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ | ||
| 420 | case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ | ||
| 421 | case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ | ||
| 422 | case 1: _hj_i += _hj_key[0]; \ | ||
| 423 | } \ | ||
| 424 | HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ | ||
| 425 | bkt = hashv & (num_bkts-1); \ | ||
| 426 | } while(0) | ||
| 427 | |||
| 428 | /* The Paul Hsieh hash function */ | ||
| 429 | #undef get16bits | ||
| 430 | #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ | ||
| 431 | || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) | ||
| 432 | #define get16bits(d) (*((const uint16_t *) (d))) | ||
| 433 | #endif | ||
| 434 | |||
| 435 | #if !defined (get16bits) | ||
| 436 | #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ | ||
| 437 | +(uint32_t)(((const uint8_t *)(d))[0]) ) | ||
| 438 | #endif | ||
| 439 | #define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ | ||
| 440 | do { \ | ||
| 441 | char *_sfh_key=(char*)(key); \ | ||
| 442 | uint32_t _sfh_tmp, _sfh_len = keylen; \ | ||
| 443 | \ | ||
| 444 | int _sfh_rem = _sfh_len & 3; \ | ||
| 445 | _sfh_len >>= 2; \ | ||
| 446 | hashv = 0xcafebabe; \ | ||
| 447 | \ | ||
| 448 | /* Main loop */ \ | ||
| 449 | for (;_sfh_len > 0; _sfh_len--) { \ | ||
| 450 | hashv += get16bits (_sfh_key); \ | ||
| 451 | _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ | ||
| 452 | hashv = (hashv << 16) ^ _sfh_tmp; \ | ||
| 453 | _sfh_key += 2*sizeof (uint16_t); \ | ||
| 454 | hashv += hashv >> 11; \ | ||
| 455 | } \ | ||
| 456 | \ | ||
| 457 | /* Handle end cases */ \ | ||
| 458 | switch (_sfh_rem) { \ | ||
| 459 | case 3: hashv += get16bits (_sfh_key); \ | ||
| 460 | hashv ^= hashv << 16; \ | ||
| 461 | hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ | ||
| 462 | hashv += hashv >> 11; \ | ||
| 463 | break; \ | ||
| 464 | case 2: hashv += get16bits (_sfh_key); \ | ||
| 465 | hashv ^= hashv << 11; \ | ||
| 466 | hashv += hashv >> 17; \ | ||
| 467 | break; \ | ||
| 468 | case 1: hashv += *_sfh_key; \ | ||
| 469 | hashv ^= hashv << 10; \ | ||
| 470 | hashv += hashv >> 1; \ | ||
| 471 | } \ | ||
| 472 | \ | ||
| 473 | /* Force "avalanching" of final 127 bits */ \ | ||
| 474 | hashv ^= hashv << 3; \ | ||
| 475 | hashv += hashv >> 5; \ | ||
| 476 | hashv ^= hashv << 4; \ | ||
| 477 | hashv += hashv >> 17; \ | ||
| 478 | hashv ^= hashv << 25; \ | ||
| 479 | hashv += hashv >> 6; \ | ||
| 480 | bkt = hashv & (num_bkts-1); \ | ||
| 481 | } while(0); | ||
| 482 | |||
| 483 | #ifdef HASH_USING_NO_STRICT_ALIASING | ||
| 484 | /* The MurmurHash exploits some CPU's (e.g. x86) tolerance for unaligned reads. | ||
| 485 | * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. | ||
| 486 | * So MurmurHash comes in two versions, the faster unaligned one and the slower | ||
| 487 | * aligned one. We only use the faster one on CPU's where we know it's safe. | ||
| 488 | * | ||
| 489 | * Note the preprocessor built-in defines can be emitted using: | ||
| 490 | * | ||
| 491 | * gcc -m64 -dM -E - < /dev/null (on gcc) | ||
| 492 | * cc -## a.c (where a.c is a simple test file) (Sun Studio) | ||
| 493 | */ | ||
| 494 | #if (defined(__i386__) || defined(__x86_64__)) | ||
| 495 | #define HASH_MUR HASH_MUR_UNALIGNED | ||
| 496 | #else | ||
| 497 | #define HASH_MUR HASH_MUR_ALIGNED | ||
| 498 | #endif | ||
| 499 | |||
| 500 | /* Appleby's MurmurHash fast version for unaligned-tolerant archs like i386 */ | ||
| 501 | #define HASH_MUR_UNALIGNED(key,keylen,num_bkts,hashv,bkt) \ | ||
| 502 | do { \ | ||
| 503 | const unsigned int _mur_m = 0x5bd1e995; \ | ||
| 504 | const int _mur_r = 24; \ | ||
| 505 | hashv = 0xcafebabe ^ keylen; \ | ||
| 506 | char *_mur_key = (char *)(key); \ | ||
| 507 | uint32_t _mur_tmp, _mur_len = keylen; \ | ||
| 508 | \ | ||
| 509 | for (;_mur_len >= 4; _mur_len-=4) { \ | ||
| 510 | _mur_tmp = *(uint32_t *)_mur_key; \ | ||
| 511 | _mur_tmp *= _mur_m; \ | ||
| 512 | _mur_tmp ^= _mur_tmp >> _mur_r; \ | ||
| 513 | _mur_tmp *= _mur_m; \ | ||
| 514 | hashv *= _mur_m; \ | ||
| 515 | hashv ^= _mur_tmp; \ | ||
| 516 | _mur_key += 4; \ | ||
| 517 | } \ | ||
| 518 | \ | ||
| 519 | switch(_mur_len) \ | ||
| 520 | { \ | ||
| 521 | case 3: hashv ^= _mur_key[2] << 16; \ | ||
| 522 | case 2: hashv ^= _mur_key[1] << 8; \ | ||
| 523 | case 1: hashv ^= _mur_key[0]; \ | ||
| 524 | hashv *= _mur_m; \ | ||
| 525 | }; \ | ||
| 526 | \ | ||
| 527 | hashv ^= hashv >> 13; \ | ||
| 528 | hashv *= _mur_m; \ | ||
| 529 | hashv ^= hashv >> 15; \ | ||
| 530 | \ | ||
| 531 | bkt = hashv & (num_bkts-1); \ | ||
| 532 | } while(0) | ||
| 533 | |||
| 534 | /* Appleby's MurmurHash version for alignment-sensitive archs like Sparc */ | ||
| 535 | #define HASH_MUR_ALIGNED(key,keylen,num_bkts,hashv,bkt) \ | ||
| 536 | do { \ | ||
| 537 | const unsigned int _mur_m = 0x5bd1e995; \ | ||
| 538 | const int _mur_r = 24; \ | ||
| 539 | hashv = 0xcafebabe ^ (keylen); \ | ||
| 540 | char *_mur_key = (char *)(key); \ | ||
| 541 | uint32_t _mur_len = keylen; \ | ||
| 542 | int _mur_align = (int)_mur_key & 3; \ | ||
| 543 | \ | ||
| 544 | if (_mur_align && (_mur_len >= 4)) { \ | ||
| 545 | unsigned _mur_t = 0, _mur_d = 0; \ | ||
| 546 | switch(_mur_align) { \ | ||
| 547 | case 1: _mur_t |= _mur_key[2] << 16; \ | ||
| 548 | case 2: _mur_t |= _mur_key[1] << 8; \ | ||
| 549 | case 3: _mur_t |= _mur_key[0]; \ | ||
| 550 | } \ | ||
| 551 | _mur_t <<= (8 * _mur_align); \ | ||
| 552 | _mur_key += 4-_mur_align; \ | ||
| 553 | _mur_len -= 4-_mur_align; \ | ||
| 554 | int _mur_sl = 8 * (4-_mur_align); \ | ||
| 555 | int _mur_sr = 8 * _mur_align; \ | ||
| 556 | \ | ||
| 557 | for (;_mur_len >= 4; _mur_len-=4) { \ | ||
| 558 | _mur_d = *(unsigned *)_mur_key; \ | ||
| 559 | _mur_t = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ | ||
| 560 | unsigned _mur_k = _mur_t; \ | ||
| 561 | _mur_k *= _mur_m; \ | ||
| 562 | _mur_k ^= _mur_k >> _mur_r; \ | ||
| 563 | _mur_k *= _mur_m; \ | ||
| 564 | hashv *= _mur_m; \ | ||
| 565 | hashv ^= _mur_k; \ | ||
| 566 | _mur_t = _mur_d; \ | ||
| 567 | _mur_key += 4; \ | ||
| 568 | } \ | ||
| 569 | _mur_d = 0; \ | ||
| 570 | if(_mur_len >= _mur_align) { \ | ||
| 571 | switch(_mur_align) { \ | ||
| 572 | case 3: _mur_d |= _mur_key[2] << 16; \ | ||
| 573 | case 2: _mur_d |= _mur_key[1] << 8; \ | ||
| 574 | case 1: _mur_d |= _mur_key[0]; \ | ||
| 575 | } \ | ||
| 576 | unsigned _mur_k = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ | ||
| 577 | _mur_k *= _mur_m; \ | ||
| 578 | _mur_k ^= _mur_k >> _mur_r; \ | ||
| 579 | _mur_k *= _mur_m; \ | ||
| 580 | hashv *= _mur_m; \ | ||
| 581 | hashv ^= _mur_k; \ | ||
| 582 | _mur_k += _mur_align; \ | ||
| 583 | _mur_len -= _mur_align; \ | ||
| 584 | \ | ||
| 585 | switch(_mur_len) \ | ||
| 586 | { \ | ||
| 587 | case 3: hashv ^= _mur_key[2] << 16; \ | ||
| 588 | case 2: hashv ^= _mur_key[1] << 8; \ | ||
| 589 | case 1: hashv ^= _mur_key[0]; \ | ||
| 590 | hashv *= _mur_m; \ | ||
| 591 | } \ | ||
| 592 | } else { \ | ||
| 593 | switch(_mur_len) \ | ||
| 594 | { \ | ||
| 595 | case 3: _mur_d ^= _mur_key[2] << 16; \ | ||
| 596 | case 2: _mur_d ^= _mur_key[1] << 8; \ | ||
| 597 | case 1: _mur_d ^= _mur_key[0]; \ | ||
| 598 | case 0: hashv ^= (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ | ||
| 599 | hashv *= _mur_m; \ | ||
| 600 | } \ | ||
| 601 | } \ | ||
| 602 | \ | ||
| 603 | hashv ^= hashv >> 13; \ | ||
| 604 | hashv *= _mur_m; \ | ||
| 605 | hashv ^= hashv >> 15; \ | ||
| 606 | } else { \ | ||
| 607 | for (;_mur_len >= 4; _mur_len-=4) { \ | ||
| 608 | unsigned _mur_k = *(unsigned*)_mur_key; \ | ||
| 609 | _mur_k *= _mur_m; \ | ||
| 610 | _mur_k ^= _mur_k >> _mur_r; \ | ||
| 611 | _mur_k *= _mur_m; \ | ||
| 612 | hashv *= _mur_m; \ | ||
| 613 | hashv ^= _mur_k; \ | ||
| 614 | _mur_key += 4; \ | ||
| 615 | } \ | ||
| 616 | switch(_mur_len) \ | ||
| 617 | { \ | ||
| 618 | case 3: hashv ^= _mur_key[2] << 16; \ | ||
| 619 | case 2: hashv ^= _mur_key[1] << 8; \ | ||
| 620 | case 1: hashv ^= _mur_key[0]; \ | ||
| 621 | hashv *= _mur_m; \ | ||
| 622 | } \ | ||
| 623 | \ | ||
| 624 | hashv ^= hashv >> 13; \ | ||
| 625 | hashv *= _mur_m; \ | ||
| 626 | hashv ^= hashv >> 15; \ | ||
| 627 | } \ | ||
| 628 | bkt = hashv & (num_bkts-1); \ | ||
| 629 | } while(0) | ||
| 630 | #endif /* HASH_USING_NO_STRICT_ALIASING */ | ||
| 631 | |||
| 632 | /* key comparison function; return 0 if keys equal */ | ||
| 633 | #define HASH_KEYCMP(a,b,len) memcmp(a,b,len) | ||
| 634 | |||
| 635 | /* iterate over items in a known bucket to find desired item */ | ||
| 636 | #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ | ||
| 637 | do { \ | ||
| 638 | if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ | ||
| 639 | else out=NULL; \ | ||
| 640 | while (out) { \ | ||
| 641 | if (out->hh.keylen == keylen_in) { \ | ||
| 642 | if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \ | ||
| 643 | } \ | ||
| 644 | if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \ | ||
| 645 | else out = NULL; \ | ||
| 646 | } \ | ||
| 647 | } while(0) | ||
| 648 | |||
| 649 | /* add an item to a bucket */ | ||
| 650 | #define HASH_ADD_TO_BKT(head,addhh) \ | ||
| 651 | do { \ | ||
| 652 | head.count++; \ | ||
| 653 | (addhh)->hh_next = head.hh_head; \ | ||
| 654 | (addhh)->hh_prev = NULL; \ | ||
| 655 | if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ | ||
| 656 | (head).hh_head=addhh; \ | ||
| 657 | if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ | ||
| 658 | && (addhh)->tbl->noexpand != 1) { \ | ||
| 659 | HASH_EXPAND_BUCKETS((addhh)->tbl); \ | ||
| 660 | } \ | ||
| 661 | } while(0) | ||
| 662 | |||
| 663 | /* remove an item from a given bucket */ | ||
| 664 | #define HASH_DEL_IN_BKT(hh,head,hh_del) \ | ||
| 665 | (head).count--; \ | ||
| 666 | if ((head).hh_head == hh_del) { \ | ||
| 667 | (head).hh_head = hh_del->hh_next; \ | ||
| 668 | } \ | ||
| 669 | if (hh_del->hh_prev) { \ | ||
| 670 | hh_del->hh_prev->hh_next = hh_del->hh_next; \ | ||
| 671 | } \ | ||
| 672 | if (hh_del->hh_next) { \ | ||
| 673 | hh_del->hh_next->hh_prev = hh_del->hh_prev; \ | ||
| 674 | } | ||
| 675 | |||
| 676 | /* Bucket expansion has the effect of doubling the number of buckets | ||
| 677 | * and redistributing the items into the new buckets. Ideally the | ||
| 678 | * items will distribute more or less evenly into the new buckets | ||
| 679 | * (the extent to which this is true is a measure of the quality of | ||
| 680 | * the hash function as it applies to the key domain). | ||
| 681 | * | ||
| 682 | * With the items distributed into more buckets, the chain length | ||
| 683 | * (item count) in each bucket is reduced. Thus by expanding buckets | ||
| 684 | * the hash keeps a bound on the chain length. This bounded chain | ||
| 685 | * length is the essence of how a hash provides constant time lookup. | ||
| 686 | * | ||
| 687 | * The calculation of tbl->ideal_chain_maxlen below deserves some | ||
| 688 | * explanation. First, keep in mind that we're calculating the ideal | ||
| 689 | * maximum chain length based on the *new* (doubled) bucket count. | ||
| 690 | * In fractions this is just n/b (n=number of items,b=new num buckets). | ||
| 691 | * Since the ideal chain length is an integer, we want to calculate | ||
| 692 | * ceil(n/b). We don't depend on floating point arithmetic in this | ||
| 693 | * hash, so to calculate ceil(n/b) with integers we could write | ||
| 694 | * | ||
| 695 | * ceil(n/b) = (n/b) + ((n%b)?1:0) | ||
| 696 | * | ||
| 697 | * and in fact a previous version of this hash did just that. | ||
| 698 | * But now we have improved things a bit by recognizing that b is | ||
| 699 | * always a power of two. We keep its base 2 log handy (call it lb), | ||
| 700 | * so now we can write this with a bit shift and logical AND: | ||
| 701 | * | ||
| 702 | * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) | ||
| 703 | * | ||
| 704 | */ | ||
| 705 | #define HASH_EXPAND_BUCKETS(tbl) \ | ||
| 706 | do { \ | ||
| 707 | unsigned _he_bkt; \ | ||
| 708 | unsigned _he_bkt_i; \ | ||
| 709 | struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ | ||
| 710 | UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ | ||
| 711 | _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ | ||
| 712 | 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ | ||
| 713 | if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ | ||
| 714 | memset(_he_new_buckets, 0, \ | ||
| 715 | 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ | ||
| 716 | tbl->ideal_chain_maxlen = \ | ||
| 717 | (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ | ||
| 718 | ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ | ||
| 719 | tbl->nonideal_items = 0; \ | ||
| 720 | for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ | ||
| 721 | { \ | ||
| 722 | _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ | ||
| 723 | while (_he_thh) { \ | ||
| 724 | _he_hh_nxt = _he_thh->hh_next; \ | ||
| 725 | HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ | ||
| 726 | _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ | ||
| 727 | if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ | ||
| 728 | tbl->nonideal_items++; \ | ||
| 729 | _he_newbkt->expand_mult = _he_newbkt->count / \ | ||
| 730 | tbl->ideal_chain_maxlen; \ | ||
| 731 | } \ | ||
| 732 | _he_thh->hh_prev = NULL; \ | ||
| 733 | _he_thh->hh_next = _he_newbkt->hh_head; \ | ||
| 734 | if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ | ||
| 735 | _he_thh; \ | ||
| 736 | _he_newbkt->hh_head = _he_thh; \ | ||
| 737 | _he_thh = _he_hh_nxt; \ | ||
| 738 | } \ | ||
| 739 | } \ | ||
| 740 | uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ | ||
| 741 | tbl->num_buckets *= 2; \ | ||
| 742 | tbl->log2_num_buckets++; \ | ||
| 743 | tbl->buckets = _he_new_buckets; \ | ||
| 744 | tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ | ||
| 745 | (tbl->ineff_expands+1) : 0; \ | ||
| 746 | if (tbl->ineff_expands > 1) { \ | ||
| 747 | tbl->noexpand=1; \ | ||
| 748 | uthash_noexpand_fyi(tbl); \ | ||
| 749 | } \ | ||
| 750 | uthash_expand_fyi(tbl); \ | ||
| 751 | } while(0) | ||
| 752 | |||
| 753 | |||
| 754 | /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ | ||
| 755 | /* Note that HASH_SORT assumes the hash handle name to be hh. | ||
| 756 | * HASH_SRT was added to allow the hash handle name to be passed in. */ | ||
| 757 | #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) | ||
| 758 | #define HASH_SRT(hh,head,cmpfcn) \ | ||
| 759 | do { \ | ||
| 760 | unsigned _hs_i; \ | ||
| 761 | unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ | ||
| 762 | struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ | ||
| 763 | if (head) { \ | ||
| 764 | _hs_insize = 1; \ | ||
| 765 | _hs_looping = 1; \ | ||
| 766 | _hs_list = &((head)->hh); \ | ||
| 767 | while (_hs_looping) { \ | ||
| 768 | _hs_p = _hs_list; \ | ||
| 769 | _hs_list = NULL; \ | ||
| 770 | _hs_tail = NULL; \ | ||
| 771 | _hs_nmerges = 0; \ | ||
| 772 | while (_hs_p) { \ | ||
| 773 | _hs_nmerges++; \ | ||
| 774 | _hs_q = _hs_p; \ | ||
| 775 | _hs_psize = 0; \ | ||
| 776 | for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ | ||
| 777 | _hs_psize++; \ | ||
| 778 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ | ||
| 779 | ((void*)((char*)(_hs_q->next) + \ | ||
| 780 | (head)->hh.tbl->hho)) : NULL); \ | ||
| 781 | if (! (_hs_q) ) break; \ | ||
| 782 | } \ | ||
| 783 | _hs_qsize = _hs_insize; \ | ||
| 784 | while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ | ||
| 785 | if (_hs_psize == 0) { \ | ||
| 786 | _hs_e = _hs_q; \ | ||
| 787 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ | ||
| 788 | ((void*)((char*)(_hs_q->next) + \ | ||
| 789 | (head)->hh.tbl->hho)) : NULL); \ | ||
| 790 | _hs_qsize--; \ | ||
| 791 | } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ | ||
| 792 | _hs_e = _hs_p; \ | ||
| 793 | _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ | ||
| 794 | ((void*)((char*)(_hs_p->next) + \ | ||
| 795 | (head)->hh.tbl->hho)) : NULL); \ | ||
| 796 | _hs_psize--; \ | ||
| 797 | } else if (( \ | ||
| 798 | cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ | ||
| 799 | DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ | ||
| 800 | ) <= 0) { \ | ||
| 801 | _hs_e = _hs_p; \ | ||
| 802 | _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ | ||
| 803 | ((void*)((char*)(_hs_p->next) + \ | ||
| 804 | (head)->hh.tbl->hho)) : NULL); \ | ||
| 805 | _hs_psize--; \ | ||
| 806 | } else { \ | ||
| 807 | _hs_e = _hs_q; \ | ||
| 808 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ | ||
| 809 | ((void*)((char*)(_hs_q->next) + \ | ||
| 810 | (head)->hh.tbl->hho)) : NULL); \ | ||
| 811 | _hs_qsize--; \ | ||
| 812 | } \ | ||
| 813 | if ( _hs_tail ) { \ | ||
| 814 | _hs_tail->next = ((_hs_e) ? \ | ||
| 815 | ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ | ||
| 816 | } else { \ | ||
| 817 | _hs_list = _hs_e; \ | ||
| 818 | } \ | ||
| 819 | _hs_e->prev = ((_hs_tail) ? \ | ||
| 820 | ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ | ||
| 821 | _hs_tail = _hs_e; \ | ||
| 822 | } \ | ||
| 823 | _hs_p = _hs_q; \ | ||
| 824 | } \ | ||
| 825 | _hs_tail->next = NULL; \ | ||
| 826 | if ( _hs_nmerges <= 1 ) { \ | ||
| 827 | _hs_looping=0; \ | ||
| 828 | (head)->hh.tbl->tail = _hs_tail; \ | ||
| 829 | DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ | ||
| 830 | } \ | ||
| 831 | _hs_insize *= 2; \ | ||
| 832 | } \ | ||
| 833 | HASH_FSCK(hh,head); \ | ||
| 834 | } \ | ||
| 835 | } while (0) | ||
| 836 | |||
| 837 | /* This function selects items from one hash into another hash. | ||
| 838 | * The end result is that the selected items have dual presence | ||
| 839 | * in both hashes. There is no copy of the items made; rather | ||
| 840 | * they are added into the new hash through a secondary hash | ||
| 841 | * hash handle that must be present in the structure. */ | ||
| 842 | #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ | ||
| 843 | do { \ | ||
| 844 | unsigned _src_bkt, _dst_bkt; \ | ||
| 845 | void *_last_elt=NULL, *_elt; \ | ||
| 846 | UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ | ||
| 847 | ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ | ||
| 848 | if (src) { \ | ||
| 849 | for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ | ||
| 850 | for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ | ||
| 851 | _src_hh; \ | ||
| 852 | _src_hh = _src_hh->hh_next) { \ | ||
| 853 | _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ | ||
| 854 | if (cond(_elt)) { \ | ||
| 855 | _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ | ||
| 856 | _dst_hh->key = _src_hh->key; \ | ||
| 857 | _dst_hh->keylen = _src_hh->keylen; \ | ||
| 858 | _dst_hh->hashv = _src_hh->hashv; \ | ||
| 859 | _dst_hh->prev = _last_elt; \ | ||
| 860 | _dst_hh->next = NULL; \ | ||
| 861 | if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ | ||
| 862 | if (!dst) { \ | ||
| 863 | DECLTYPE_ASSIGN(dst,_elt); \ | ||
| 864 | HASH_MAKE_TABLE(hh_dst,dst); \ | ||
| 865 | } else { \ | ||
| 866 | _dst_hh->tbl = (dst)->hh_dst.tbl; \ | ||
| 867 | } \ | ||
| 868 | HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ | ||
| 869 | HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ | ||
| 870 | (dst)->hh_dst.tbl->num_items++; \ | ||
| 871 | _last_elt = _elt; \ | ||
| 872 | _last_elt_hh = _dst_hh; \ | ||
| 873 | } \ | ||
| 874 | } \ | ||
| 875 | } \ | ||
| 876 | } \ | ||
| 877 | HASH_FSCK(hh_dst,dst); \ | ||
| 878 | } while (0) | ||
| 879 | |||
| 880 | #define HASH_CLEAR(hh,head) \ | ||
| 881 | do { \ | ||
| 882 | if (head) { \ | ||
| 883 | uthash_free((head)->hh.tbl->buckets, \ | ||
| 884 | (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ | ||
| 885 | uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ | ||
| 886 | (head)=NULL; \ | ||
| 887 | } \ | ||
| 888 | } while(0) | ||
| 889 | |||
| 890 | #ifdef NO_DECLTYPE | ||
| 891 | #define HASH_ITER(hh,head,el,tmp) \ | ||
| 892 | for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ | ||
| 893 | el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) | ||
| 894 | #else | ||
| 895 | #define HASH_ITER(hh,head,el,tmp) \ | ||
| 896 | for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ | ||
| 897 | el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) | ||
| 898 | #endif | ||
| 899 | |||
| 900 | /* obtain a count of items in the hash */ | ||
| 901 | #define HASH_COUNT(head) HASH_CNT(hh,head) | ||
| 902 | #define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) | ||
| 903 | |||
| 904 | typedef struct UT_hash_bucket { | ||
| 905 | struct UT_hash_handle *hh_head; | ||
| 906 | unsigned count; | ||
| 907 | |||
| 908 | /* expand_mult is normally set to 0. In this situation, the max chain length | ||
| 909 | * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If | ||
| 910 | * the bucket's chain exceeds this length, bucket expansion is triggered). | ||
| 911 | * However, setting expand_mult to a non-zero value delays bucket expansion | ||
| 912 | * (that would be triggered by additions to this particular bucket) | ||
| 913 | * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. | ||
| 914 | * (The multiplier is simply expand_mult+1). The whole idea of this | ||
| 915 | * multiplier is to reduce bucket expansions, since they are expensive, in | ||
| 916 | * situations where we know that a particular bucket tends to be overused. | ||
| 917 | * It is better to let its chain length grow to a longer yet-still-bounded | ||
| 918 | * value, than to do an O(n) bucket expansion too often. | ||
| 919 | */ | ||
| 920 | unsigned expand_mult; | ||
| 921 | |||
| 922 | } UT_hash_bucket; | ||
| 923 | |||
| 924 | /* random signature used only to find hash tables in external analysis */ | ||
| 925 | #define HASH_SIGNATURE 0xa0111fe1 | ||
| 926 | #define HASH_BLOOM_SIGNATURE 0xb12220f2 | ||
| 927 | |||
| 928 | typedef struct UT_hash_table { | ||
| 929 | UT_hash_bucket *buckets; | ||
| 930 | unsigned num_buckets, log2_num_buckets; | ||
| 931 | unsigned num_items; | ||
| 932 | struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ | ||
| 933 | ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ | ||
| 934 | |||
| 935 | /* in an ideal situation (all buckets used equally), no bucket would have | ||
| 936 | * more than ceil(#items/#buckets) items. that's the ideal chain length. */ | ||
| 937 | unsigned ideal_chain_maxlen; | ||
| 938 | |||
| 939 | /* nonideal_items is the number of items in the hash whose chain position | ||
| 940 | * exceeds the ideal chain maxlen. these items pay the penalty for an uneven | ||
| 941 | * hash distribution; reaching them in a chain traversal takes >ideal steps */ | ||
| 942 | unsigned nonideal_items; | ||
| 943 | |||
| 944 | /* ineffective expands occur when a bucket doubling was performed, but | ||
| 945 | * afterward, more than half the items in the hash had nonideal chain | ||
| 946 | * positions. If this happens on two consecutive expansions we inhibit any | ||
| 947 | * further expansion, as it's not helping; this happens when the hash | ||
| 948 | * function isn't a good fit for the key domain. When expansion is inhibited | ||
| 949 | * the hash will still work, albeit no longer in constant time. */ | ||
| 950 | unsigned ineff_expands, noexpand; | ||
| 951 | |||
| 952 | uint32_t signature; /* used only to find hash tables in external analysis */ | ||
| 953 | #ifdef HASH_BLOOM | ||
| 954 | uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ | ||
| 955 | uint8_t *bloom_bv; | ||
| 956 | char bloom_nbits; | ||
| 957 | #endif | ||
| 958 | |||
| 959 | } UT_hash_table; | ||
| 960 | |||
| 961 | typedef struct UT_hash_handle { | ||
| 962 | struct UT_hash_table *tbl; | ||
| 963 | void *prev; /* prev element in app order */ | ||
| 964 | void *next; /* next element in app order */ | ||
| 965 | struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ | ||
| 966 | struct UT_hash_handle *hh_next; /* next hh in bucket order */ | ||
| 967 | void *key; /* ptr to enclosing struct's key */ | ||
| 968 | unsigned keylen; /* enclosing struct's key len */ | ||
| 969 | unsigned hashv; /* result of hash-fcn(key) */ | ||
| 970 | } UT_hash_handle; | ||
| 971 | |||
| 972 | #endif /* UTHASH_H */ | ||
| diff --git a/libs/cocos2d/Support/utlist.h b/libs/cocos2d/Support/utlist.h new file mode 100755 index 0000000..34c725b --- /dev/null +++ b/libs/cocos2d/Support/utlist.h | |||
| @@ -0,0 +1,490 @@ | |||
| 1 | /* | ||
| 2 | Copyright (c) 2007-2010, Troy D. Hanson http://uthash.sourceforge.net | ||
| 3 | All rights reserved. | ||
| 4 | |||
| 5 | Redistribution and use in source and binary forms, with or without | ||
| 6 | modification, are permitted provided that the following conditions are met: | ||
| 7 | |||
| 8 | * Redistributions of source code must retain the above copyright | ||
| 9 | notice, this list of conditions and the following disclaimer. | ||
| 10 | |||
| 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | ||
| 12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||
| 13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | ||
| 14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | ||
| 15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
| 16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
| 17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
| 18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
| 19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
| 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #ifndef UTLIST_H | ||
| 25 | #define UTLIST_H | ||
| 26 | |||
| 27 | #define UTLIST_VERSION 1.9.1 | ||
| 28 | |||
| 29 | /* | ||
| 30 | * This file contains macros to manipulate singly and doubly-linked lists. | ||
| 31 | * | ||
| 32 | * 1. LL_ macros: singly-linked lists. | ||
| 33 | * 2. DL_ macros: doubly-linked lists. | ||
| 34 | * 3. CDL_ macros: circular doubly-linked lists. | ||
| 35 | * | ||
| 36 | * To use singly-linked lists, your structure must have a "next" pointer. | ||
| 37 | * To use doubly-linked lists, your structure must "prev" and "next" pointers. | ||
| 38 | * Either way, the pointer to the head of the list must be initialized to NULL. | ||
| 39 | * | ||
| 40 | * ----------------.EXAMPLE ------------------------- | ||
| 41 | * struct item { | ||
| 42 | * int id; | ||
| 43 | * struct item *prev, *next; | ||
| 44 | * } | ||
| 45 | * | ||
| 46 | * struct item *list = NULL: | ||
| 47 | * | ||
| 48 | * int main() { | ||
| 49 | * struct item *item; | ||
| 50 | * ... allocate and populate item ... | ||
| 51 | * DL_APPEND(list, item); | ||
| 52 | * } | ||
| 53 | * -------------------------------------------------- | ||
| 54 | * | ||
| 55 | * For doubly-linked lists, the append and delete macros are O(1) | ||
| 56 | * For singly-linked lists, append and delete are O(n) but prepend is O(1) | ||
| 57 | * The sort macro is O(n log(n)) for all types of single/double/circular lists. | ||
| 58 | */ | ||
| 59 | |||
| 60 | /* These macros use decltype or the earlier __typeof GNU extension. | ||
| 61 | As decltype is only available in newer compilers (VS2010 or gcc 4.3+ | ||
| 62 | when compiling c++ code), this code uses whatever method is needed | ||
| 63 | or, for VS2008 where neither is available, uses casting workarounds. */ | ||
| 64 | #ifdef _MSC_VER /* MS compiler */ | ||
| 65 | #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ | ||
| 66 | #define LDECLTYPE(x) decltype(x) | ||
| 67 | #else /* VS2008 or older (or VS2010 in C mode) */ | ||
| 68 | #define NO_DECLTYPE | ||
| 69 | #define LDECLTYPE(x) char* | ||
| 70 | #endif | ||
| 71 | #else /* GNU, Sun and other compilers */ | ||
| 72 | #define LDECLTYPE(x) __typeof(x) | ||
| 73 | #endif | ||
| 74 | |||
| 75 | /* for VS2008 we use some workarounds to get around the lack of decltype, | ||
| 76 | * namely, we always reassign our tmp variable to the list head if we need | ||
| 77 | * to dereference its prev/next pointers, and save/restore the real head.*/ | ||
| 78 | #ifdef NO_DECLTYPE | ||
| 79 | #define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } | ||
| 80 | #define _NEXT(elt,list) ((char*)((list)->next)) | ||
| 81 | #define _NEXTASGN(elt,list,to) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } | ||
| 82 | #define _PREV(elt,list) ((char*)((list)->prev)) | ||
| 83 | #define _PREVASGN(elt,list,to) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } | ||
| 84 | #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } | ||
| 85 | #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } | ||
| 86 | #else | ||
| 87 | #define _SV(elt,list) | ||
| 88 | #define _NEXT(elt,list) ((elt)->next) | ||
| 89 | #define _NEXTASGN(elt,list,to) ((elt)->next)=(to) | ||
| 90 | #define _PREV(elt,list) ((elt)->prev) | ||
| 91 | #define _PREVASGN(elt,list,to) ((elt)->prev)=(to) | ||
| 92 | #define _RS(list) | ||
| 93 | #define _CASTASGN(a,b) (a)=(b) | ||
| 94 | #endif | ||
| 95 | |||
| 96 | /****************************************************************************** | ||
| 97 | * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * | ||
| 98 | * Unwieldy variable names used here to avoid shadowing passed-in variables. * | ||
| 99 | *****************************************************************************/ | ||
| 100 | #define LL_SORT(list, cmp) \ | ||
| 101 | do { \ | ||
| 102 | LDECLTYPE(list) _ls_p; \ | ||
| 103 | LDECLTYPE(list) _ls_q; \ | ||
| 104 | LDECLTYPE(list) _ls_e; \ | ||
| 105 | LDECLTYPE(list) _ls_tail; \ | ||
| 106 | LDECLTYPE(list) _ls_oldhead; \ | ||
| 107 | LDECLTYPE(list) _tmp; \ | ||
| 108 | int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ | ||
| 109 | if (list) { \ | ||
| 110 | _ls_insize = 1; \ | ||
| 111 | _ls_looping = 1; \ | ||
| 112 | while (_ls_looping) { \ | ||
| 113 | _CASTASGN(_ls_p,list); \ | ||
| 114 | _CASTASGN(_ls_oldhead,list); \ | ||
| 115 | list = NULL; \ | ||
| 116 | _ls_tail = NULL; \ | ||
| 117 | _ls_nmerges = 0; \ | ||
| 118 | while (_ls_p) { \ | ||
| 119 | _ls_nmerges++; \ | ||
| 120 | _ls_q = _ls_p; \ | ||
| 121 | _ls_psize = 0; \ | ||
| 122 | for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ | ||
| 123 | _ls_psize++; \ | ||
| 124 | _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \ | ||
| 125 | if (!_ls_q) break; \ | ||
| 126 | } \ | ||
| 127 | _ls_qsize = _ls_insize; \ | ||
| 128 | while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ | ||
| 129 | if (_ls_psize == 0) { \ | ||
| 130 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
| 131 | } else if (_ls_qsize == 0 || !_ls_q) { \ | ||
| 132 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
| 133 | } else if (cmp(_ls_p,_ls_q) <= 0) { \ | ||
| 134 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
| 135 | } else { \ | ||
| 136 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
| 137 | } \ | ||
| 138 | if (_ls_tail) { \ | ||
| 139 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ | ||
| 140 | } else { \ | ||
| 141 | _CASTASGN(list,_ls_e); \ | ||
| 142 | } \ | ||
| 143 | _ls_tail = _ls_e; \ | ||
| 144 | } \ | ||
| 145 | _ls_p = _ls_q; \ | ||
| 146 | } \ | ||
| 147 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \ | ||
| 148 | if (_ls_nmerges <= 1) { \ | ||
| 149 | _ls_looping=0; \ | ||
| 150 | } \ | ||
| 151 | _ls_insize *= 2; \ | ||
| 152 | } \ | ||
| 153 | } else _tmp=NULL; /* quiet gcc unused variable warning */ \ | ||
| 154 | } while (0) | ||
| 155 | |||
| 156 | #define DL_SORT(list, cmp) \ | ||
| 157 | do { \ | ||
| 158 | LDECLTYPE(list) _ls_p; \ | ||
| 159 | LDECLTYPE(list) _ls_q; \ | ||
| 160 | LDECLTYPE(list) _ls_e; \ | ||
| 161 | LDECLTYPE(list) _ls_tail; \ | ||
| 162 | LDECLTYPE(list) _ls_oldhead; \ | ||
| 163 | LDECLTYPE(list) _tmp; \ | ||
| 164 | int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ | ||
| 165 | if (list) { \ | ||
| 166 | _ls_insize = 1; \ | ||
| 167 | _ls_looping = 1; \ | ||
| 168 | while (_ls_looping) { \ | ||
| 169 | _CASTASGN(_ls_p,list); \ | ||
| 170 | _CASTASGN(_ls_oldhead,list); \ | ||
| 171 | list = NULL; \ | ||
| 172 | _ls_tail = NULL; \ | ||
| 173 | _ls_nmerges = 0; \ | ||
| 174 | while (_ls_p) { \ | ||
| 175 | _ls_nmerges++; \ | ||
| 176 | _ls_q = _ls_p; \ | ||
| 177 | _ls_psize = 0; \ | ||
| 178 | for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ | ||
| 179 | _ls_psize++; \ | ||
| 180 | _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \ | ||
| 181 | if (!_ls_q) break; \ | ||
| 182 | } \ | ||
| 183 | _ls_qsize = _ls_insize; \ | ||
| 184 | while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ | ||
| 185 | if (_ls_psize == 0) { \ | ||
| 186 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
| 187 | } else if (_ls_qsize == 0 || !_ls_q) { \ | ||
| 188 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
| 189 | } else if (cmp(_ls_p,_ls_q) <= 0) { \ | ||
| 190 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
| 191 | } else { \ | ||
| 192 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
| 193 | } \ | ||
| 194 | if (_ls_tail) { \ | ||
| 195 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ | ||
| 196 | } else { \ | ||
| 197 | _CASTASGN(list,_ls_e); \ | ||
| 198 | } \ | ||
| 199 | _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \ | ||
| 200 | _ls_tail = _ls_e; \ | ||
| 201 | } \ | ||
| 202 | _ls_p = _ls_q; \ | ||
| 203 | } \ | ||
| 204 | _CASTASGN(list->prev, _ls_tail); \ | ||
| 205 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \ | ||
| 206 | if (_ls_nmerges <= 1) { \ | ||
| 207 | _ls_looping=0; \ | ||
| 208 | } \ | ||
| 209 | _ls_insize *= 2; \ | ||
| 210 | } \ | ||
| 211 | } else _tmp=NULL; /* quiet gcc unused variable warning */ \ | ||
| 212 | } while (0) | ||
| 213 | |||
| 214 | #define CDL_SORT(list, cmp) \ | ||
| 215 | do { \ | ||
| 216 | LDECLTYPE(list) _ls_p; \ | ||
| 217 | LDECLTYPE(list) _ls_q; \ | ||
| 218 | LDECLTYPE(list) _ls_e; \ | ||
| 219 | LDECLTYPE(list) _ls_tail; \ | ||
| 220 | LDECLTYPE(list) _ls_oldhead; \ | ||
| 221 | LDECLTYPE(list) _tmp; \ | ||
| 222 | LDECLTYPE(list) _tmp2; \ | ||
| 223 | int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ | ||
| 224 | if (list) { \ | ||
| 225 | _ls_insize = 1; \ | ||
| 226 | _ls_looping = 1; \ | ||
| 227 | while (_ls_looping) { \ | ||
| 228 | _CASTASGN(_ls_p,list); \ | ||
| 229 | _CASTASGN(_ls_oldhead,list); \ | ||
| 230 | list = NULL; \ | ||
| 231 | _ls_tail = NULL; \ | ||
| 232 | _ls_nmerges = 0; \ | ||
| 233 | while (_ls_p) { \ | ||
| 234 | _ls_nmerges++; \ | ||
| 235 | _ls_q = _ls_p; \ | ||
| 236 | _ls_psize = 0; \ | ||
| 237 | for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ | ||
| 238 | _ls_psize++; \ | ||
| 239 | _SV(_ls_q,list); \ | ||
| 240 | if (_NEXT(_ls_q,list) == _ls_oldhead) { \ | ||
| 241 | _ls_q = NULL; \ | ||
| 242 | } else { \ | ||
| 243 | _ls_q = _NEXT(_ls_q,list); \ | ||
| 244 | } \ | ||
| 245 | _RS(list); \ | ||
| 246 | if (!_ls_q) break; \ | ||
| 247 | } \ | ||
| 248 | _ls_qsize = _ls_insize; \ | ||
| 249 | while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ | ||
| 250 | if (_ls_psize == 0) { \ | ||
| 251 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
| 252 | if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ | ||
| 253 | } else if (_ls_qsize == 0 || !_ls_q) { \ | ||
| 254 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
| 255 | if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ | ||
| 256 | } else if (cmp(_ls_p,_ls_q) <= 0) { \ | ||
| 257 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
| 258 | if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ | ||
| 259 | } else { \ | ||
| 260 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
| 261 | if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ | ||
| 262 | } \ | ||
| 263 | if (_ls_tail) { \ | ||
| 264 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ | ||
| 265 | } else { \ | ||
| 266 | _CASTASGN(list,_ls_e); \ | ||
| 267 | } \ | ||
| 268 | _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \ | ||
| 269 | _ls_tail = _ls_e; \ | ||
| 270 | } \ | ||
| 271 | _ls_p = _ls_q; \ | ||
| 272 | } \ | ||
| 273 | _CASTASGN(list->prev,_ls_tail); \ | ||
| 274 | _CASTASGN(_tmp2,list); \ | ||
| 275 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp2); _RS(list); \ | ||
| 276 | if (_ls_nmerges <= 1) { \ | ||
| 277 | _ls_looping=0; \ | ||
| 278 | } \ | ||
| 279 | _ls_insize *= 2; \ | ||
| 280 | } \ | ||
| 281 | } else _tmp=NULL; /* quiet gcc unused variable warning */ \ | ||
| 282 | } while (0) | ||
| 283 | |||
| 284 | /****************************************************************************** | ||
| 285 | * singly linked list macros (non-circular) * | ||
| 286 | *****************************************************************************/ | ||
| 287 | #define LL_PREPEND(head,add) \ | ||
| 288 | do { \ | ||
| 289 | (add)->next = head; \ | ||
| 290 | head = add; \ | ||
| 291 | } while (0) | ||
| 292 | |||
| 293 | #define LL_APPEND(head,add) \ | ||
| 294 | do { \ | ||
| 295 | LDECLTYPE(head) _tmp; \ | ||
| 296 | (add)->next=NULL; \ | ||
| 297 | if (head) { \ | ||
| 298 | _tmp = head; \ | ||
| 299 | while (_tmp->next) { _tmp = _tmp->next; } \ | ||
| 300 | _tmp->next=(add); \ | ||
| 301 | } else { \ | ||
| 302 | (head)=(add); \ | ||
| 303 | } \ | ||
| 304 | } while (0) | ||
| 305 | |||
| 306 | #define LL_DELETE(head,del) \ | ||
| 307 | do { \ | ||
| 308 | LDECLTYPE(head) _tmp; \ | ||
| 309 | if ((head) == (del)) { \ | ||
| 310 | (head)=(head)->next; \ | ||
| 311 | } else { \ | ||
| 312 | _tmp = head; \ | ||
| 313 | while (_tmp->next && (_tmp->next != (del))) { \ | ||
| 314 | _tmp = _tmp->next; \ | ||
| 315 | } \ | ||
| 316 | if (_tmp->next) { \ | ||
| 317 | _tmp->next = ((del)->next); \ | ||
| 318 | } \ | ||
| 319 | } \ | ||
| 320 | } while (0) | ||
| 321 | |||
| 322 | /* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ | ||
| 323 | #define LL_APPEND_VS2008(head,add) \ | ||
| 324 | do { \ | ||
| 325 | if (head) { \ | ||
| 326 | (add)->next = head; /* use add->next as a temp variable */ \ | ||
| 327 | while ((add)->next->next) { (add)->next = (add)->next->next; } \ | ||
| 328 | (add)->next->next=(add); \ | ||
| 329 | } else { \ | ||
| 330 | (head)=(add); \ | ||
| 331 | } \ | ||
| 332 | (add)->next=NULL; \ | ||
| 333 | } while (0) | ||
| 334 | |||
| 335 | #define LL_DELETE_VS2008(head,del) \ | ||
| 336 | do { \ | ||
| 337 | if ((head) == (del)) { \ | ||
| 338 | (head)=(head)->next; \ | ||
| 339 | } else { \ | ||
| 340 | char *_tmp = (char*)(head); \ | ||
| 341 | while (head->next && (head->next != (del))) { \ | ||
| 342 | head = head->next; \ | ||
| 343 | } \ | ||
| 344 | if (head->next) { \ | ||
| 345 | head->next = ((del)->next); \ | ||
| 346 | } \ | ||
| 347 | { \ | ||
| 348 | char **_head_alias = (char**)&(head); \ | ||
| 349 | *_head_alias = _tmp; \ | ||
| 350 | } \ | ||
| 351 | } \ | ||
| 352 | } while (0) | ||
| 353 | #ifdef NO_DECLTYPE | ||
| 354 | #undef LL_APPEND | ||
| 355 | #define LL_APPEND LL_APPEND_VS2008 | ||
| 356 | #undef LL_DELETE | ||
| 357 | #define LL_DELETE LL_DELETE_VS2008 | ||
| 358 | #endif | ||
| 359 | /* end VS2008 replacements */ | ||
| 360 | |||
| 361 | #define LL_FOREACH(head,el) \ | ||
| 362 | for(el=head;el;el=el->next) | ||
| 363 | |||
| 364 | #define LL_FOREACH_SAFE(head,el,tmp) \ | ||
| 365 | for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) | ||
| 366 | |||
| 367 | #define LL_SEARCH_SCALAR(head,out,field,val) \ | ||
| 368 | do { \ | ||
| 369 | LL_FOREACH(head,out) { \ | ||
| 370 | if ((out)->field == (val)) break; \ | ||
| 371 | } \ | ||
| 372 | } while(0) | ||
| 373 | |||
| 374 | #define LL_SEARCH(head,out,elt,cmp) \ | ||
| 375 | do { \ | ||
| 376 | LL_FOREACH(head,out) { \ | ||
| 377 | if ((cmp(out,elt))==0) break; \ | ||
| 378 | } \ | ||
| 379 | } while(0) | ||
| 380 | |||
| 381 | /****************************************************************************** | ||
| 382 | * doubly linked list macros (non-circular) * | ||
| 383 | *****************************************************************************/ | ||
| 384 | #define DL_PREPEND(head,add) \ | ||
| 385 | do { \ | ||
| 386 | (add)->next = head; \ | ||
| 387 | if (head) { \ | ||
| 388 | (add)->prev = (head)->prev; \ | ||
| 389 | (head)->prev = (add); \ | ||
| 390 | } else { \ | ||
| 391 | (add)->prev = (add); \ | ||
| 392 | } \ | ||
| 393 | (head) = (add); \ | ||
| 394 | } while (0) | ||
| 395 | |||
| 396 | #define DL_APPEND(head,add) \ | ||
| 397 | do { \ | ||
| 398 | if (head) { \ | ||
| 399 | (add)->prev = (head)->prev; \ | ||
| 400 | (head)->prev->next = (add); \ | ||
| 401 | (head)->prev = (add); \ | ||
| 402 | (add)->next = NULL; \ | ||
| 403 | } else { \ | ||
| 404 | (head)=(add); \ | ||
| 405 | (head)->prev = (head); \ | ||
| 406 | (head)->next = NULL; \ | ||
| 407 | } \ | ||
| 408 | } while (0); | ||
| 409 | |||
| 410 | #define DL_DELETE(head,del) \ | ||
| 411 | do { \ | ||
| 412 | if ((del)->prev == (del)) { \ | ||
| 413 | (head)=NULL; \ | ||
| 414 | } else if ((del)==(head)) { \ | ||
| 415 | (del)->next->prev = (del)->prev; \ | ||
| 416 | (head) = (del)->next; \ | ||
| 417 | } else { \ | ||
| 418 | (del)->prev->next = (del)->next; \ | ||
| 419 | if ((del)->next) { \ | ||
| 420 | (del)->next->prev = (del)->prev; \ | ||
| 421 | } else { \ | ||
| 422 | (head)->prev = (del)->prev; \ | ||
| 423 | } \ | ||
| 424 | } \ | ||
| 425 | } while (0); | ||
| 426 | |||
| 427 | |||
| 428 | #define DL_FOREACH(head,el) \ | ||
| 429 | for(el=head;el;el=el->next) | ||
| 430 | |||
| 431 | /* this version is safe for deleting the elements during iteration */ | ||
| 432 | #define DL_FOREACH_SAFE(head,el,tmp) \ | ||
| 433 | for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) | ||
| 434 | |||
| 435 | /* these are identical to their singly-linked list counterparts */ | ||
| 436 | #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR | ||
| 437 | #define DL_SEARCH LL_SEARCH | ||
| 438 | |||
| 439 | /****************************************************************************** | ||
| 440 | * circular doubly linked list macros * | ||
| 441 | *****************************************************************************/ | ||
| 442 | #define CDL_PREPEND(head,add) \ | ||
| 443 | do { \ | ||
| 444 | if (head) { \ | ||
| 445 | (add)->prev = (head)->prev; \ | ||
| 446 | (add)->next = (head); \ | ||
| 447 | (head)->prev = (add); \ | ||
| 448 | (add)->prev->next = (add); \ | ||
| 449 | } else { \ | ||
| 450 | (add)->prev = (add); \ | ||
| 451 | (add)->next = (add); \ | ||
| 452 | } \ | ||
| 453 | (head)=(add); \ | ||
| 454 | } while (0) | ||
| 455 | |||
| 456 | #define CDL_DELETE(head,del) \ | ||
| 457 | do { \ | ||
| 458 | if ( ((head)==(del)) && ((head)->next == (head))) { \ | ||
| 459 | (head) = 0L; \ | ||
| 460 | } else { \ | ||
| 461 | (del)->next->prev = (del)->prev; \ | ||
| 462 | (del)->prev->next = (del)->next; \ | ||
| 463 | if ((del) == (head)) (head)=(del)->next; \ | ||
| 464 | } \ | ||
| 465 | } while (0); | ||
| 466 | |||
| 467 | #define CDL_FOREACH(head,el) \ | ||
| 468 | for(el=head;el;el=(el->next==head ? 0L : el->next)) | ||
| 469 | |||
| 470 | #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ | ||
| 471 | for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ | ||
| 472 | (el) && ((tmp2)=(el)->next, 1); \ | ||
| 473 | ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) | ||
| 474 | |||
| 475 | #define CDL_SEARCH_SCALAR(head,out,field,val) \ | ||
| 476 | do { \ | ||
| 477 | CDL_FOREACH(head,out) { \ | ||
| 478 | if ((out)->field == (val)) break; \ | ||
| 479 | } \ | ||
| 480 | } while(0) | ||
| 481 | |||
| 482 | #define CDL_SEARCH(head,out,elt,cmp) \ | ||
| 483 | do { \ | ||
| 484 | CDL_FOREACH(head,out) { \ | ||
| 485 | if ((cmp(out,elt))==0) break; \ | ||
| 486 | } \ | ||
| 487 | } while(0) | ||
| 488 | |||
| 489 | #endif /* UTLIST_H */ | ||
| 490 | |||
