diff options
author | Dmitry Isaikin <isaikin@corp.mail.ru> | 2016-02-03 14:03:58 +0300 |
---|---|---|
committer | Dmitry Isaikin <isaikin@corp.mail.ru> | 2016-02-03 14:12:05 +0300 |
commit | 5ba469e045e88217eedaa13cfb3ff27ac469617a (patch) | |
tree | c2a461cf4f0c079e8c08bd81bcbd76eb4d86dde4 /src/core/basetypes | |
parent | 35bf8538ed83c4085eff072fc52faee047680d3e (diff) |
Remove extra memory copying while fetching attachment
Diffstat (limited to 'src/core/basetypes')
-rw-r--r-- | src/core/basetypes/MCData.cpp | 67 | ||||
-rw-r--r-- | src/core/basetypes/MCData.h | 14 | ||||
-rw-r--r-- | src/core/basetypes/MCDataMac.mm | 16 |
3 files changed, 80 insertions, 17 deletions
diff --git a/src/core/basetypes/MCData.cpp b/src/core/basetypes/MCData.cpp index 079344da..9c6d0cae 100644 --- a/src/core/basetypes/MCData.cpp +++ b/src/core/basetypes/MCData.cpp @@ -39,6 +39,25 @@ static int isPowerOfTwo (unsigned int x) void Data::allocate(unsigned int length, bool force) { + if (mExternallyAllocatedMemory) { + // We don't know how this memory was allocated. + // Possibly this memory is readonly. + // So we need fallback to malloc'ed implementation. + + unsigned int bytes_len = 0; + char * bytes = NULL; + if (mBytes) { + bytes_len = mLength; + bytes = (char *) malloc(mLength); + memcpy(bytes, mBytes, mLength); + } + + reset(); + mBytes = bytes; + mLength = bytes_len; + mAllocated = bytes_len; + } + if (length <= mAllocated) return; @@ -62,37 +81,46 @@ void Data::allocate(unsigned int length, bool force) void Data::reset() { - free(mBytes); + if (mExternallyAllocatedMemory) { + if (mBytes && mBytesDeallocator) { + mBytesDeallocator(mBytes, mLength); + } + } else { + free(mBytes); + } + init(); +} + +void Data::init() +{ mAllocated = 0; mLength = 0; mBytes = NULL; + mExternallyAllocatedMemory = false; + mBytesDeallocator = NULL; } Data::Data() { - mBytes = NULL; - reset(); + init(); } Data::Data(Data * otherData) : Object() { - mBytes = NULL; - reset(); + init(); appendData(otherData); } Data::Data(const char * bytes, unsigned int length) { - mBytes = NULL; - reset(); + init(); allocate(length, true); appendBytes(bytes, length); } Data::Data(int capacity) { - mBytes = NULL; - reset(); + init(); allocate(capacity, true); } @@ -484,9 +512,19 @@ String * Data::charsetWithFilteredHTML(bool filterHTML, String * hintCharset) #endif } +void Data::takeBytesOwnership(char * bytes, unsigned int length, BytesDeallocator bytesDeallocator) +{ + reset(); + mBytes = bytes; + mLength = length; + mAllocated = length; + mExternallyAllocatedMemory = true; + mBytesDeallocator = bytesDeallocator; +} + void Data::takeBytesOwnership(char * bytes, unsigned int length) { - free(mBytes); + reset(); mBytes = (char *) bytes; mLength = length; } @@ -567,6 +605,10 @@ static size_t uudecode(char * text, size_t size) return count; } +static void decodedPartDeallocator(char * decoded, unsigned int decoded_length) { + mailmime_decoded_part_free(decoded); +}; + Data * Data::decodedDataUsingEncoding(Encoding encoding) { const char * text; @@ -606,8 +648,9 @@ Data * Data::decodedDataUsingEncoding(Encoding encoding) cur_token = 0; mailmime_part_parse(text, text_length, &cur_token, mime_encoding, &decoded, &decoded_length); - data = Data::dataWithBytes(decoded, (unsigned int) decoded_length); - mailmime_decoded_part_free(decoded); + + data = Data::data(); + data->takeBytesOwnership(decoded, (unsigned int) decoded_length, decodedPartDeallocator); return data; } case EncodingUUEncode: diff --git a/src/core/basetypes/MCData.h b/src/core/basetypes/MCData.h index 0bb1bc07..4151757e 100644 --- a/src/core/basetypes/MCData.h +++ b/src/core/basetypes/MCData.h @@ -16,7 +16,9 @@ namespace mailcore { class String; - + + typedef void (*BytesDeallocator)(char * bytes, unsigned int length); + class MAILCORE_EXPORT Data : public Object { public: Data(); @@ -49,6 +51,13 @@ namespace mailcore { public: // private virtual String * charsetWithFilteredHTML(bool filterHTML, String * hintCharset = NULL); + + /* Replace contents of Data instance with contents of a given bytes without extra copying. + Memory ownership transferred from client code to the Data instance. + Data destructor will call bytesDeallocator function for memory releasing. + */ + void takeBytesOwnership(char * bytes, unsigned int length, BytesDeallocator bytesDeallocator); + #ifdef __APPLE__ virtual CFDataRef destructiveNSData(); #endif @@ -66,7 +75,10 @@ namespace mailcore { char * mBytes; unsigned int mLength; unsigned int mAllocated; + bool mExternallyAllocatedMemory; + BytesDeallocator mBytesDeallocator; void allocate(unsigned int length, bool force = false); + void init(); void reset(); String * charsetWithFilteredHTMLWithoutHint(bool filterHTML); void takeBytesOwnership(char * bytes, unsigned int length); diff --git a/src/core/basetypes/MCDataMac.mm b/src/core/basetypes/MCDataMac.mm index 8081b1f9..589e8b59 100644 --- a/src/core/basetypes/MCDataMac.mm +++ b/src/core/basetypes/MCDataMac.mm @@ -14,9 +14,17 @@ using namespace mailcore; CFDataRef Data::destructiveNSData() { - NSData * result = [NSData dataWithBytesNoCopy:(void *) mBytes length:mLength]; - mBytes = NULL; - mAllocated = 0; - mLength = 0; + NSData * result; + if (mExternallyAllocatedMemory) { + BytesDeallocator deallocator = mBytesDeallocator; + result = [[[NSData alloc] initWithBytesNoCopy:mBytes length:mLength deallocator:^(void * bytes, NSUInteger length) { + if (deallocator) { + deallocator((char *)bytes, (unsigned int)length); + } + }] autorelease]; + } else { + result = [NSData dataWithBytesNoCopy:(void *) mBytes length:mLength]; + } + init(); return (CFDataRef) result; } |