Index: src/OFDataArray.h ================================================================== --- src/OFDataArray.h +++ src/OFDataArray.h @@ -30,12 +30,11 @@ * for OFDataArrays with item size 1. */ @interface OFDataArray: OFObject { uint8_t *_items; - size_t _count; - size_t _itemSize; + size_t _count, _itemSize, _capacity; } #ifdef OF_HAVE_PROPERTIES @property (readonly) void *items; @property (readonly) size_t count; @@ -56,10 +55,21 @@ * @param itemSize The size of a single element in the OFDataArray * @return A new autoreleased OFDataArray */ + (instancetype)dataArrayWithItemSize: (size_t)itemSize; +/*! + * @brief Creates a new OFDataArray with enough memory to hold the specified + * number of items which all have the same specified size. + * + * @param itemSize The size of a single element in the OFDataArray + * @param capacity The initial capacity for the OFDataArray + * @return A new autoreleased OFDataArray + */ ++ (instancetype)dataArrayWithItemSize: (size_t)itemSize + capacity: (size_t)capacity; + /*! * @brief Creates a new OFDataArary with an item size of 1, containing the data * of the specified file. * * @param path The path of the file @@ -101,10 +111,22 @@ * @param itemSize The size of a single element in the OFDataArray * @return An initialized OFDataArray */ - initWithItemSize: (size_t)itemSize; +/*! + * @brief Initializes an already allocated OFDataArray with enough memory to + * hold the specified number of items which all have the same specified + * size. + * + * @param itemSize The size of a single element in the OFDataArray + * @param capacity The initial capacity for the OFDataArray + * @return An initialized OFDataArray + */ +- initWithItemSize: (size_t)itemSize + capacity: (size_t)capacity; + /*! * @brief Initializes an already allocated OFDataArray with an item size of 1, * containing the data of the specified file. * * @param path The path of the file Index: src/OFDataArray.m ================================================================== --- src/OFDataArray.m +++ src/OFDataArray.m @@ -56,10 +56,17 @@ + (instancetype)dataArrayWithItemSize: (size_t)itemSize { return [[[self alloc] initWithItemSize: itemSize] autorelease]; } + ++ (instancetype)dataArrayWithItemSize: (size_t)itemSize + capacity: (size_t)capacity +{ + return [[[self alloc] initWithItemSize: itemSize + capacity: capacity] autorelease]; +} + (instancetype)dataArrayWithContentsOfFile: (OFString*)path { return [[[self alloc] initWithContentsOfFile: path] autorelease]; } @@ -80,18 +87,22 @@ return [[[self alloc] initWithBase64EncodedString: string] autorelease]; } - init { - self = [super init]; + return [self initWithItemSize: 1 + capacity: 0]; +} - _itemSize = 1; - - return self; +- initWithItemSize: (size_t)itemSize +{ + return [self initWithItemSize: itemSize + capacity: 0]; } - initWithItemSize: (size_t)itemSize + capacity: (size_t)capacity { self = [super init]; if (itemSize == 0) { Class c = [self class]; @@ -98,24 +109,32 @@ [self release]; @throw [OFInvalidArgumentException exceptionWithClass: c selector: _cmd]; } + _items = [self allocMemoryWithSize: itemSize + count: capacity]; + _itemSize = itemSize; + _capacity = capacity; return self; } - initWithContentsOfFile: (OFString*)path { - self = [super init]; - @try { OFFile *file = [[OFFile alloc] initWithPath: path mode: @"rb"]; + off_t size = [OFFile sizeOfFileAtPath: path]; - _itemSize = 1; + if (size > SIZE_MAX) + @throw [OFOutOfRangeException + exceptionWithClass: [self class]]; + + self = [self initWithItemSize: 1 + capacity: size]; @try { size_t pageSize = [OFSystemInfo pageSize]; char *buffer = [self allocMemoryWithSize: pageSize]; @@ -169,10 +188,14 @@ @throw [OFHTTPRequestFailedException exceptionWithClass: [request class] request: request reply: reply]; + /* + * TODO: This can be optimized by allocating a data array with the + * capacity from the Content-Length header. + */ self = [[reply readDataArrayTillEndOfStream] retain]; headers = [reply headers]; if ((contentLength = [headers objectForKey: @"Content-Length"]) != nil) if ([self count] != (size_t)[contentLength decimalValue]) @@ -240,15 +263,14 @@ return self; } - initWithBase64EncodedString: (OFString*)string { - self = [super init]; + self = [self initWithItemSize: 1 + capacity: [string length] / 3]; @try { - _itemSize = 1; - if (!of_base64_decode(self, [string cStringWithEncoding: OF_STRING_ENCODING_ASCII], [string cStringLengthWithEncoding: OF_STRING_ENCODING_ASCII])) { Class c = [self class]; [self release]; @@ -262,14 +284,10 @@ return self; } - initWithSerialization: (OFXMLElement*)element { - self = [super init]; - - _itemSize = 1; - @try { void *pool = objc_autoreleasePoolPush(); OFString *stringValue; if (![[element name] isEqual: [self className]] || @@ -278,16 +296,11 @@ exceptionWithClass: [self class] selector: _cmd]; stringValue = [element stringValue]; - if (!of_base64_decode(self, [stringValue - cStringWithEncoding: OF_STRING_ENCODING_ASCII], - [stringValue cStringLengthWithEncoding: - OF_STRING_ENCODING_ASCII])) - @throw [OFInvalidFormatException - exceptionWithClass: [self class]]; + self = [self initWithBase64EncodedString: stringValue]; objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; @@ -338,13 +351,16 @@ - (void)addItem: (const void*)item { if (SIZE_MAX - _count < 1) @throw [OFOutOfRangeException exceptionWithClass: [self class]]; - _items = [self resizeMemory: _items - size: _itemSize - count: _count + 1]; + if (_count + 1 > _capacity) { + _items = [self resizeMemory: _items + size: _itemSize + count: _count + 1]; + _capacity = _count + 1; + } memcpy(_items + _count * _itemSize, item, _itemSize); _count++; } @@ -361,13 +377,16 @@ count: (size_t)count { if (count > SIZE_MAX - count) @throw [OFOutOfRangeException exceptionWithClass: [self class]]; - _items = [self resizeMemory: _items - size: _itemSize - count: _count + count]; + if (_count + count > _capacity) { + _items = [self resizeMemory: _items + size: _itemSize + count: _count + count]; + _capacity = _count + count; + } memcpy(_items + _count * _itemSize, items, count * _itemSize); _count += count; } @@ -376,13 +395,16 @@ count: (size_t)count { if (count > SIZE_MAX - _count || index > _count) @throw [OFOutOfRangeException exceptionWithClass: [self class]]; - _items = [self resizeMemory: _items - size: _itemSize - count: _count + count]; + if (_count + count > _capacity) { + _items = [self resizeMemory: _items + size: _itemSize + count: _count + count]; + _capacity = _count + count; + } memmove(_items + (index + count) * _itemSize, _items + index * _itemSize, (_count - index) * _itemSize); memcpy(_items + index * _itemSize, items, count * _itemSize); @@ -407,10 +429,11 @@ _count -= range.length; @try { _items = [self resizeMemory: _items size: _itemSize count: _count]; + _capacity = _count; } @catch (OFOutOfMemoryException *e) { /* We don't really care, as we only made it smaller */ } } @@ -422,10 +445,11 @@ _count--; @try { _items = [self resizeMemory: _items size: _itemSize count: _count]; + _capacity = _count; } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only made it smaller */ } } @@ -433,15 +457,17 @@ { [self freeMemory: _items]; _items = NULL; _count = 0; + _capacity = 0; } - copy { - OFDataArray *copy = [[[self class] alloc] initWithItemSize: _itemSize]; + OFDataArray *copy = [[[self class] alloc] initWithItemSize: _itemSize + capacity: _count]; [copy addItems: _items count: _count]; return copy; @@ -590,10 +616,21 @@ return [element autorelease]; } @end @implementation OFBigDataArray +- initWithItemSize: (size_t)itemSize + capacity: (size_t)capacity +{ + size_t lastPageByte = [OFSystemInfo pageSize] - 1; + + capacity = (capacity * itemSize + lastPageByte) & ~lastPageByte; + + return [super initWithItemSize: itemSize + capacity: capacity]; +} + - (void)addItem: (const void*)item { size_t size, lastPageByte; if (SIZE_MAX - _count < 1 || _count + 1 > SIZE_MAX / _itemSize) @@ -600,13 +637,15 @@ @throw [OFOutOfRangeException exceptionWithClass: [self class]]; lastPageByte = [OFSystemInfo pageSize] - 1; size = ((_count + 1) * _itemSize + lastPageByte) & ~lastPageByte; - if (_size != size) + if (size > _capacity) { _items = [self resizeMemory: _items size: size]; + _capacity = size; + } memcpy(_items + _count * _itemSize, item, _itemSize); _count++; _size = size; @@ -621,13 +660,15 @@ @throw [OFOutOfRangeException exceptionWithClass: [self class]]; lastPageByte = [OFSystemInfo pageSize] - 1; size = ((_count + count) * _itemSize + lastPageByte) & ~lastPageByte; - if (_size != size) + if (size > _capacity) { _items = [self resizeMemory: _items size: size]; + _capacity = size; + } memcpy(_items + _count * _itemSize, items, count * _itemSize); _count += count; _size = size; @@ -644,13 +685,15 @@ @throw [OFOutOfRangeException exceptionWithClass: [self class]]; lastPageByte = [OFSystemInfo pageSize] - 1; size = ((_count + count) * _itemSize + lastPageByte) & ~lastPageByte; - if (_size != size) + if (size > _capacity) { _items = [self resizeMemory: _items size: size]; + _capacity = size; + } memmove(_items + (index + count) * _itemSize, _items + index * _itemSize, (_count - index) * _itemSize); memcpy(_items + index * _itemSize, items, count * _itemSize); @@ -676,10 +719,11 @@ if (_size != size && size >= pageSize) { @try { _items = [self resizeMemory: _items size: size]; + _capacity = size; } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only made it smaller */ } _size = size; @@ -699,10 +743,11 @@ if (_size != size && size >= pageSize) { @try { _items = [self resizeMemory: _items size: size]; + _capacity = size; } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only made it smaller */ } _size = size; @@ -714,13 +759,14 @@ size_t pageSize = [OFSystemInfo pageSize]; @try { _items = [self resizeMemory: _items size: pageSize]; + _capacity = pageSize; _size = pageSize; } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only made it smaller */ } _count = 0; } @end Index: src/OFFile.h ================================================================== --- src/OFFile.h +++ src/OFFile.h @@ -274,21 +274,21 @@ extern "C" { #endif /*! @file */ /*! - * @brief The standard input stream. + * @brief The standard input stream as an OFStream instance. */ extern OFStream *of_stdin; /*! - * @brief The standard output stream. + * @brief The standard output stream as an OFStream instance. */ extern OFStream *of_stdout; /*! - * @brief The standard error stream. + * @brief The standard error stream as an OFStream instance. */ extern OFStream *of_stderr; #ifdef __cplusplus } #endif Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -836,10 +836,13 @@ - (void*)allocMemoryWithSize: (size_t)size { void *pointer; struct pre_mem *preMem; + + if OF_UNLIKELY (size == 0) + return NULL; if OF_UNLIKELY (size > SIZE_MAX - PRE_IVARS_ALIGN) @throw [OFOutOfRangeException exceptionWithClass: [self class]]; if OF_UNLIKELY ((pointer = malloc(PRE_MEM_ALIGN + size)) == NULL) @@ -862,13 +865,10 @@ } - (void*)allocMemoryWithSize: (size_t)size count: (size_t)count { - if OF_UNLIKELY (size == 0 || count == 0) - return NULL; - if OF_UNLIKELY (count > SIZE_MAX / size) @throw [OFOutOfRangeException exceptionWithClass: [self class]]; return [self allocMemoryWithSize: size * count]; }