aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/basetypes
diff options
context:
space:
mode:
authorGravatar Dmitry Isaikin <isaikin@corp.mail.ru>2016-02-03 14:03:58 +0300
committerGravatar Dmitry Isaikin <isaikin@corp.mail.ru>2016-02-03 14:12:05 +0300
commit5ba469e045e88217eedaa13cfb3ff27ac469617a (patch)
treec2a461cf4f0c079e8c08bd81bcbd76eb4d86dde4 /src/core/basetypes
parent35bf8538ed83c4085eff072fc52faee047680d3e (diff)
Remove extra memory copying while fetching attachment
Diffstat (limited to 'src/core/basetypes')
-rw-r--r--src/core/basetypes/MCData.cpp67
-rw-r--r--src/core/basetypes/MCData.h14
-rw-r--r--src/core/basetypes/MCDataMac.mm16
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;
}