From 99dd6b8a038402c8db31ee623dac7472606e7def Mon Sep 17 00:00:00 2001 From: alexpeshkoff Date: Wed, 26 May 2004 16:10:56 +0000 Subject: [PATCH] optimize string performance with the price of 4 additional bytes per string --- src/common/classes/fb_string.cpp | 55 ++++++++++++++----------- src/include/fb_string.h | 71 ++++++++++++++++---------------- 2 files changed, 66 insertions(+), 60 deletions(-) diff --git a/src/common/classes/fb_string.cpp b/src/common/classes/fb_string.cpp index 074c3cb387..200f40eda1 100644 --- a/src/common/classes/fb_string.cpp +++ b/src/common/classes/fb_string.cpp @@ -118,8 +118,8 @@ namespace Firebird { , __FILE__, __LINE__ #endif ); - x.newStorage[n] = 0; - return x.newStorage; + bigStorage[n] = 0; + return bigStorage; } AbstractString::pointer AbstractString::baseAppend(size_type n) { @@ -130,10 +130,10 @@ namespace Firebird { #endif ); if (x.oldStorage) { - memcpy(x.newStorage, x.oldStorage, x.oldSize); + memcpy(bigStorage, x.oldStorage, x.oldSize); } - x.newStorage[length()] = 0; - return &x.newStorage[x.oldSize]; + bigStorage[length()] = 0; + return &bigStorage[x.oldSize]; } AbstractString::pointer AbstractString::baseInsert(size_type p0, size_type n) { @@ -147,16 +147,16 @@ namespace Firebird { #endif ); if (x.oldStorage) { - memcpy(x.newStorage, x.oldStorage, p0); - memcpy(&x.newStorage[p0 + n], + memcpy(bigStorage, x.oldStorage, p0); + memcpy(&bigStorage[p0 + n], &x.oldStorage[p0], x.oldSize - p0); } else { - memmove(&x.newStorage[p0 + n], &x.newStorage[p0], + memmove(&bigStorage[p0 + n], &bigStorage[p0], x.oldSize - p0); } - x.newStorage[length()] = 0; - return &x.newStorage[p0]; + bigStorage[length()] = 0; + return &bigStorage[p0]; } void AbstractString::baseErase(size_type p0, size_type n) { @@ -168,18 +168,23 @@ namespace Firebird { #endif ); if (x.oldStorage) { - memcpy(x.newStorage, x.oldStorage, p0); - memcpy(&x.newStorage[p0], &x.oldStorage[p0 + n], + memcpy(bigStorage, x.oldStorage, p0); + memcpy(&bigStorage[p0], &x.oldStorage[p0 + n], x.oldSize - (p0 + n)); } else { - memmove(&x.newStorage[p0], - &x.newStorage[p0 + n], x.oldSize - (p0 + n)); + memmove(&bigStorage[p0], + &bigStorage[p0 + n], x.oldSize - (p0 + n)); } - x.newStorage[length()] = 0; + bigStorage[length()] = 0; } -/* void AbstractString::reserve(size_type n) { +/* + *** Firebird::string uses algorithm of freeing memory used by + *** very long strings, when length of string becomes MUCH smaller. + *** Obviously, it conflicts with reserve() STL-like method. + *** Therefore - no implementation for a while. + void AbstractString::reserve(size_type n) { if (n <= actualSize) { return; } @@ -195,9 +200,9 @@ namespace Firebird { forced = n; } if (x.oldStorage) { - memcpy(x.newStorage, x.oldStorage, l); + memcpy(bigStorage, x.oldStorage, l); } - x.newStorage[l] = 0; + bigStorage[l] = 0; }*/ void AbstractString::resize(size_type n, char_type c) { @@ -211,12 +216,12 @@ namespace Firebird { #endif ); if (x.oldStorage) { - memcpy(x.newStorage, x.oldStorage, n < x.oldSize ? n : x.oldSize); + memcpy(bigStorage, x.oldStorage, n < x.oldSize ? n : x.oldSize); } if (n > x.oldSize) { - memset(&x.newStorage[x.oldSize], c, n - x.oldSize); + memset(&bigStorage[x.oldSize], c, n - x.oldSize); } - x.newStorage[n] = 0; + bigStorage[n] = 0; } AbstractString::size_type AbstractString::rfind(const_pointer s, size_type pos) const { @@ -373,12 +378,12 @@ namespace Firebird { #endif ); if (x.oldStorage) { - memcpy(x.newStorage, b, NewLength); + memcpy(bigStorage, b, NewLength); } - else if (b != x.newStorage) { - memmove(x.newStorage, b, NewLength); + else if (b != bigStorage) { + memmove(bigStorage, b, NewLength); } - x.newStorage[NewLength] = 0; + bigStorage[NewLength] = 0; } void AbstractString::printf(const char* format,...) { diff --git a/src/include/fb_string.h b/src/include/fb_string.h index b74435b2b5..ba0e949254 100644 --- a/src/include/fb_string.h +++ b/src/include/fb_string.h @@ -54,13 +54,8 @@ namespace Firebird static const size_type npos; enum {smallStorageSize = 32, reserveSize = 16, keepSize = 512}; protected: - union { - char_type smallStorage[smallStorageSize]; -// BRS 14/05/04: ISO C++ doesn't allow anonymous struct inside anonymous union -// struct { - char_type* bigStorage; -// }; - }; + char_type smallStorage[smallStorageSize]; + char_type* bigStorage; unsigned short userSize, actualSize; private: inline void checkPos(size_type pos) const { @@ -96,33 +91,37 @@ namespace Firebird inline pointer createStorage(size_type uSize) { checkSize(uSize); userSize = uSize; - if (uSize < smallStorageSize) { + if (uSize < smallStorageSize) + { actualSize = smallStorageSize; - smallStorage[uSize] = 0; - return smallStorage; + bigStorage = smallStorage; } - allocateStorage(uSize + else + { + allocateStorage(uSize #ifdef DEV_BUILD - , __FILE__, __LINE__ + , __FILE__, __LINE__ #endif - ); + ); + } bigStorage[uSize] = 0; return bigStorage; } - // Returns (possibly reallocated) newStorage for current string, - // setting values for oldStorage (if string is not - // updated inplace) and oldSize. oldStorage - // should be released after use if oldSize >= smallStorageSize + + // Temporary structure returned by openStorage() struct StoragePair { - pointer newStorage, oldStorage; + pointer oldStorage; size_type oldSize; - char_type oldSmallStorage[smallStorageSize]; ~StoragePair() { if (oldSize >= AbstractString::smallStorageSize) delete[] oldStorage; } }; friend struct StoragePair; + // Creates (possibly reallocated) bigStorage for new string. + // Sets values for oldStorage + // (if string is not updated inplace) and oldSize. + // oldStorage will be released in StoragePair's destructor. inline void openStorage(StoragePair& rc, size_type newSize #ifdef DEV_BUILD , const char *file, int line @@ -132,36 +131,37 @@ namespace Firebird rc.oldStorage = 0; rc.oldSize = userSize; userSize = newSize; - if (newSize < smallStorageSize) { - if (actualSize > smallStorageSize) { + + // new string fits into smallStorage + if (newSize < smallStorageSize) + { + // old bigStorage should be deallocated + if (actualSize > smallStorageSize) + { rc.oldStorage = bigStorage; } - rc.newStorage = smallStorage; + bigStorage = smallStorage; actualSize = smallStorageSize; return; } + + // size change was small enough not to reallocate memory if (newSize < actualSize && newSize + keepSize > actualSize) { - rc.newStorage = bigStorage; return; } - if (actualSize <= smallStorageSize) { - memcpy(rc.oldSmallStorage, smallStorage, rc.oldSize); - rc.oldStorage = rc.oldSmallStorage; - } - else { - rc.oldStorage = bigStorage; - } + + // do memory reallocation + rc.oldStorage = bigStorage; allocateStorage(newSize #ifdef DEV_BUILD , file, line #endif ); - rc.newStorage = bigStorage; } + // Returns pointer to current storage. inline pointer getStorage() { - return actualSize <= smallStorageSize ? - smallStorage : bigStorage; + return bigStorage; } protected: AbstractString(size_type sizeL, const_pointer datap); @@ -169,12 +169,14 @@ namespace Firebird const_pointer p2, size_type n2); AbstractString(const AbstractString& v); inline AbstractString() { + bigStorage = smallStorage; actualSize = smallStorageSize; userSize = 0; smallStorage[0] = 0; } AbstractString(size_type sizeL, char_type c); inline explicit AbstractString(MemoryPool& p) : AutoStorage(p) { + bigStorage = smallStorage; actualSize = smallStorageSize; userSize = 0; smallStorage[0] = 0; @@ -202,8 +204,7 @@ namespace Firebird void baseTrim(TrimType WhereTrim, const_pointer ToTrim); public: inline const_pointer c_str() const { - return actualSize <= smallStorageSize ? - smallStorage : bigStorage; + return bigStorage; } inline size_type length() const { return userSize;