Index: src/OFSeekableStream.m ================================================================== --- src/OFSeekableStream.m +++ src/OFSeekableStream.m @@ -52,12 +52,12 @@ offset -= _readBufferLength; offset = [self lowlevelSeekToOffset: offset whence: whence]; - [self freeMemory: _readBuffer]; - _readBuffer = NULL; + [self freeMemory: _readBufferMemory]; + _readBuffer = _readBufferMemory = NULL; _readBufferLength = 0; return offset; } @end Index: src/OFStream.h ================================================================== --- src/OFStream.h +++ src/OFStream.h @@ -92,11 +92,11 @@ OFCopying> { #if !defined(OF_SEEKABLE_STREAM_M) && !defined(OF_TCP_SOCKET_M) @private #endif - char *_readBuffer, *_writeBuffer; + char *_readBuffer, *_readBufferMemory, *_writeBuffer; size_t _readBufferLength, _writeBufferLength; bool _writeBuffered, _waitingForDelimiter; @protected bool _blocking; } Index: src/OFStream.m ================================================================== --- src/OFStream.m +++ src/OFStream.m @@ -47,10 +47,12 @@ #import "OFOutOfRangeException.h" #import "OFSetOptionFailedException.h" #import "of_asprintf.h" +#define MIN_READ_SIZE 512 + @implementation OFStream @synthesize OF_isWaitingForDelimiter = _waitingForDelimiter; #ifndef OF_WINDOWS + (void)initialize @@ -110,33 +112,59 @@ } - (size_t)readIntoBuffer: (void*)buffer length: (size_t)length { - if (_readBufferLength == 0) + if (_readBufferLength == 0) { + /* + * For small sizes, it is cheaper to read more and cache the + * remainder - even if that means more copying of data - than + * to do a syscall for every read. + */ + if (length < MIN_READ_SIZE) { + char tmp[MIN_READ_SIZE], *readBuffer; + size_t bytesRead; + + bytesRead = [self + lowlevelReadIntoBuffer: tmp + length: MIN_READ_SIZE]; + + if (bytesRead > length) { + memcpy(buffer, tmp, length); + + readBuffer = [self allocMemoryWithSize: + bytesRead - length]; + memcpy(readBuffer, tmp + length, + bytesRead - length); + + _readBuffer = _readBufferMemory = readBuffer; + _readBufferLength = bytesRead - length; + + return length; + } else { + memcpy(buffer, tmp, bytesRead); + return bytesRead; + } + } + return [self lowlevelReadIntoBuffer: buffer length: length]; + } if (length >= _readBufferLength) { size_t ret = _readBufferLength; memcpy(buffer, _readBuffer, _readBufferLength); - [self freeMemory: _readBuffer]; - _readBuffer = NULL; + [self freeMemory: _readBufferMemory]; + _readBuffer = _readBufferMemory = NULL; _readBufferLength = 0; return ret; } else { - char *tmp; - - tmp = [self allocMemoryWithSize: _readBufferLength - length]; - memcpy(tmp, _readBuffer + length, _readBufferLength - length); - memcpy(buffer, _readBuffer, length); - [self freeMemory: _readBuffer]; - _readBuffer = tmp; + _readBuffer += length; _readBufferLength -= length; return length; } } @@ -568,18 +596,11 @@ ret = [OFString stringWithCString: _readBuffer encoding: encoding length: retLength]; - readBuffer = [self allocMemoryWithSize: - _readBufferLength - i - 1]; - if (readBuffer != NULL) - memcpy(readBuffer, _readBuffer + i + 1, - _readBufferLength - i - 1); - - [self freeMemory: _readBuffer]; - _readBuffer = readBuffer; + _readBuffer += i + 1; _readBufferLength -= i + 1; _waitingForDelimiter = false; return ret; } @@ -604,12 +625,12 @@ ret = [OFString stringWithCString: _readBuffer encoding: encoding length: retLength]; - [self freeMemory: _readBuffer]; - _readBuffer = NULL; + [self freeMemory: _readBufferMemory]; + _readBuffer = _readBufferMemory = NULL; _readBufferLength = 0; _waitingForDelimiter = false; return ret; } @@ -642,25 +663,34 @@ ret = [OFString stringWithCString: rcs encoding: encoding length: rl]; } @catch (id e) { - /* - * Append data to readBuffer to prevent - * loss of data due to wrong encoding. - */ - _readBuffer = [self - resizeMemory: _readBuffer - size: _readBufferLength + - bufferLength]; - - if (_readBuffer != NULL) - memcpy(_readBuffer + + if (bufferLength > 0) { + /* + * Append data to _readBuffer + * to prevent loss of data due + * to wrong encoding. + */ + readBuffer = [self + allocMemoryWithSize: + _readBufferLength + + bufferLength]; + + memcpy(readBuffer, _readBuffer, + _readBufferLength); + memcpy(readBuffer + _readBufferLength, buffer, bufferLength); - _readBufferLength += bufferLength; + [self freeMemory: + _readBufferMemory]; + _readBuffer = readBuffer; + _readBufferMemory = readBuffer; + _readBufferLength += + bufferLength; + } @throw e; } @finally { [self freeMemory: retCString]; } @@ -669,33 +699,32 @@ allocMemoryWithSize: bufferLength - i - 1]; if (readBuffer != NULL) memcpy(readBuffer, buffer + i + 1, bufferLength - i - 1); - [self freeMemory: _readBuffer]; - _readBuffer = readBuffer; + [self freeMemory: _readBufferMemory]; + _readBuffer = _readBufferMemory = readBuffer; _readBufferLength = bufferLength - i - 1; _waitingForDelimiter = false; return ret; } } /* There was no newline or \0 */ - _readBuffer = [self resizeMemory: _readBuffer - size: _readBufferLength + - bufferLength]; - - /* - * It's possible that _readBufferLength + bufferLength is 0 and - * thus _readBuffer was set to NULL by resizeMemory:size:. - */ - if (_readBuffer != NULL) - memcpy(_readBuffer + _readBufferLength, + if (bufferLength > 0) { + readBuffer = [self allocMemoryWithSize: + _readBufferLength + bufferLength]; + + memcpy(readBuffer, _readBuffer, _readBufferLength); + memcpy(readBuffer + _readBufferLength, buffer, bufferLength); - _readBufferLength += bufferLength; + [self freeMemory: _readBufferMemory]; + _readBuffer = _readBufferMemory = readBuffer; + _readBufferLength += bufferLength; + } } @finally { [self freeMemory: buffer]; } _waitingForDelimiter = true; @@ -787,18 +816,11 @@ ret = [OFString stringWithCString: _readBuffer encoding: encoding length: i + 1 - delimiterLength]; - readBuffer = [self allocMemoryWithSize: - _readBufferLength - i - 1]; - if (readBuffer != NULL) - memcpy(readBuffer, _readBuffer + i + 1, - _readBufferLength - i - 1); - - [self freeMemory: _readBuffer]; - _readBuffer = readBuffer; + _readBuffer += i + 1; _readBufferLength -= i + 1; _waitingForDelimiter = false; return ret; } @@ -818,12 +840,12 @@ ret = [OFString stringWithCString: _readBuffer encoding: encoding length: _readBufferLength]; - [self freeMemory: _readBuffer]; - _readBuffer = NULL; + [self freeMemory: _readBufferMemory]; + _readBuffer = _readBufferMemory = NULL; _readBufferLength = 0; _waitingForDelimiter = false; return ret; } @@ -872,33 +894,32 @@ bufferLength - i - 1]; if (readBuffer != NULL) memcpy(readBuffer, buffer + i + 1, bufferLength - i - 1); - [self freeMemory: _readBuffer]; - _readBuffer = readBuffer; + [self freeMemory: _readBufferMemory]; + _readBuffer = _readBufferMemory = readBuffer; _readBufferLength = bufferLength - i - 1; _waitingForDelimiter = false; return ret; } } /* Neither the delimiter nor \0 was found */ - _readBuffer = [self resizeMemory: _readBuffer - size: _readBufferLength + - bufferLength]; - - /* - * It's possible that _readBufferLength + bufferLength is 0 and - * thus _readBuffer was set to NULL by resizeMemory:size:. - */ - if (_readBuffer != NULL) - memcpy(_readBuffer + _readBufferLength, + if (bufferLength > 0) { + readBuffer = [self allocMemoryWithSize: + _readBufferLength + bufferLength]; + + memcpy(readBuffer, _readBuffer, _readBufferLength); + memcpy(readBuffer + _readBufferLength, buffer, bufferLength); - _readBufferLength += bufferLength; + [self freeMemory: _readBufferMemory]; + _readBuffer = _readBufferMemory = readBuffer; + _readBufferLength += bufferLength; + } } @finally { [self freeMemory: buffer]; } _waitingForDelimiter = true; @@ -1499,22 +1520,24 @@ #endif - (void)unreadFromBuffer: (const void*)buffer length: (size_t)length { + char *readBuffer; + if (length > SIZE_MAX - _readBufferLength) @throw [OFOutOfRangeException exception]; - _readBuffer = [self resizeMemory: _readBuffer - size: _readBufferLength + length]; + readBuffer = [self allocMemoryWithSize: _readBufferLength + length]; + memcpy(readBuffer, buffer, length); + memcpy(readBuffer + length, _readBuffer, _readBufferLength); - memmove(_readBuffer + length, _readBuffer, _readBufferLength); - memcpy(_readBuffer, buffer, length); - + [self freeMemory: _readBuffer]; + _readBuffer = _readBufferMemory = readBuffer; _readBufferLength += length; } - (void)close { OF_UNRECOGNIZED_SELECTOR } @end