diff options
author | Dimitri van Heesch <dimitri@stack.nl> | 2014-10-21 19:31:35 (GMT) |
---|---|---|
committer | Dimitri van Heesch <dimitri@stack.nl> | 2014-10-21 19:31:35 (GMT) |
commit | a9dcbfe28625673f4d13bc5b3cde694c24062e19 (patch) | |
tree | 978138b6c6ba28a6e62a6dd9cfb0f5e2a6de6391 /qtools | |
parent | 9323ae470ad514586706dc8647501361fe208f36 (diff) | |
download | Doxygen-a9dcbfe28625673f4d13bc5b3cde694c24062e19.zip Doxygen-a9dcbfe28625673f4d13bc5b3cde694c24062e19.tar.gz Doxygen-a9dcbfe28625673f4d13bc5b3cde694c24062e19.tar.bz2 |
Fixed refcounting bug in new string implementation
Diffstat (limited to 'qtools')
-rw-r--r-- | qtools/qcstring.h | 27 | ||||
-rw-r--r-- | qtools/rcstring.h | 791 |
2 files changed, 15 insertions, 803 deletions
diff --git a/qtools/qcstring.h b/qtools/qcstring.h index 7170455..5c3a0de 100644 --- a/qtools/qcstring.h +++ b/qtools/qcstring.h @@ -498,19 +498,22 @@ public: } StringRep &operator=(const StringRep &s) { - if (!u.s.isShort) - { - u.l.d->dispose(); - } - if (s.u.s.isShort) // copy by value - { - u.s = s.u.s; - } - else // copy by reference + if (&s!=this) { - u.l.isShort=FALSE; - u.l.d = s.u.l.d; - u.l.d->refCount++; + if (!u.s.isShort) + { + u.l.d->dispose(); + } + if (s.u.s.isShort) // copy by value + { + u.s = s.u.s; + } + else // copy by reference + { + u.l.isShort=FALSE; + u.l.d = s.u.l.d; + u.l.d->refCount++; + } } return *this; } diff --git a/qtools/rcstring.h b/qtools/rcstring.h deleted file mode 100644 index 01b5a5c..0000000 --- a/qtools/rcstring.h +++ /dev/null @@ -1,791 +0,0 @@ -/****************************************************************************** - * - * Copyright (C) 1997-2004 by Dimitri van Heesch. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software - * for any purpose. It is provided "as is" without express or implied warranty. - * See the GNU General Public License for more details. - * - * Documents produced by Doxygen are derivative works derived from the - * input used in their production; they are not affected by this license. - * - */ - -#ifndef RCSTRING_H -#define RCSTRING_H - -#define RCString QCString - -#ifndef QT_H -#include "qarray.h" -#endif // QT_H - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#if !defined(_OS_WIN32_) || defined(__MINGW32__) -#include <stdint.h> -#endif - -#if defined(_OS_SUN_) && defined(_CC_GNU_) -#include <strings.h> -#endif - -#include <assert.h> - -class QGString; - -/***************************************************************************** - Fixes and workarounds for some platforms - *****************************************************************************/ - -#if defined(_OS_HPUX_) -// HP-UX has badly defined strstr() etc. -// ### fix in 3.0: change hack_* to qt_hack_* -// by the way HP-UX is probably right, the standard has evolved and -// we'll have to adapt to it -inline char *hack_strstr( const char *s1, const char *s2 ) -{ return (char *)strstr(s1, s2); } -inline char *hack_strchr( const char *s, int c ) -{ return (char *)strchr(s, c); } -inline char *hack_strrchr( const char *s, int c ) -{ return (char *)strrchr(s, c); } -#define strstr(s1,s2) hack_strstr((s1),(s2)) -#define strchr(s,c) hack_strchr((s),(c)) -#define strrchr(s,c) hack_strrchr((s),(c)) -#endif - -/***************************************************************************** - Safe and portable C string functions; extensions to standard string.h - *****************************************************************************/ - -Q_EXPORT void *qmemmove( void *dst, const void *src, uint len ); - -#if defined(_OS_SUN_) || defined(_CC_OC_) -#define memmove(s1,s2,n) qmemmove((s1),(s2),(n)) -#endif - -#if defined(_OS_WIN32_) -#define qsnprintf _snprintf -#else -#define qsnprintf snprintf -#endif - -Q_EXPORT char *qstrdup( const char * ); - -Q_EXPORT inline uint cstrlen( const char *str ) -{ return (uint)strlen(str); } - -Q_EXPORT inline uint qstrlen( const char *str ) -{ return str ? (uint)strlen(str) : 0; } - -Q_EXPORT inline char *cstrcpy( char *dst, const char *src ) -{ return strcpy(dst,src); } - -Q_EXPORT inline char *qstrcpy( char *dst, const char *src ) -{ return src ? strcpy(dst, src) : 0; } - -Q_EXPORT char * qstrncpy(char *src,const char *dst, uint len); - -Q_EXPORT inline int cstrcmp( const char *str1, const char *str2 ) -{ return strcmp(str1,str2); } - -Q_EXPORT inline int qstrcmp( const char *str1, const char *str2 ) -{ return (str1 && str2) ? strcmp(str1,str2) : (int)((intptr_t)str2 - (intptr_t)str1); } - -Q_EXPORT inline int cstrncmp( const char *str1, const char *str2, uint len ) -{ return strncmp(str1,str2,len); } - -Q_EXPORT inline int qstrncmp( const char *str1, const char *str2, uint len ) -{ return (str1 && str2) ? strncmp(str1,str2,len) : - (int)((intptr_t)str2 - (intptr_t)str1); } - -Q_EXPORT int qstricmp( const char *str1, const char *str2 ); - -Q_EXPORT int qstrnicmp( const char *str1, const char *str2, uint len ); - -/***************************************************************************** - QByteArray class - *****************************************************************************/ - -#if defined(Q_TEMPLATEDLL) -template class Q_EXPORT QArray<char>; -#endif -typedef QArray<char> QByteArray; - -/***************************************************************************** - QByteArray stream functions - *****************************************************************************/ -#ifndef QT_NO_DATASTREAM -Q_EXPORT QDataStream &operator<<( QDataStream &, const QByteArray & ); -Q_EXPORT QDataStream &operator>>( QDataStream &, QByteArray & ); -#endif - -class QRegExp; - -/** This is an alternative implementation of QCString. It provides basically - * the same functions but uses reference counting and copy on write. - */ -class RCString -{ -public: - /** creates an empty string */ - RCString() - { - } - - /** destroys the string */ - ~RCString() - { - } - - /** makes a copy of a string. */ - RCString( const RCString &s ) : m_rep(s.m_rep) - { - } - - /** creates a string with room for size characters - * @param[in] size the number of character to allocate (including the 0-terminator) - */ - RCString( int size ) : m_rep(size) - { - } - - /** creates a string from a plain C string. - * @param[in] str A zero terminated C string. When 0 an empty string is created. - */ - RCString( const char *str ) : m_rep(str) - { - } - - /** creates a string from \a str and copies over the first \a maxlen characters. */ - RCString( const char *str, uint maxlen ) : m_rep(str,maxlen) - { - } - - /** replaces the contents by that of string \a s. */ - RCString &operator=( const RCString &s ) - { - m_rep = s.m_rep; - return *this; - } - - /** replaces the contents by that of C string \a str. */ - RCString &operator=( const char *str) - { - m_rep = str; - return *this; - } - - /** Returns TRUE iff the string is empty. Equivalent to isEmpty(). */ - bool isNull() const - { - return m_rep.isEmpty(); - } - - /** Returns TRUE iff the string is empty */ - bool isEmpty() const - { - return m_rep.isEmpty(); - } - - /** Returns the length of the string, excluding the 0-terminator. Equivalent to size(). */ - uint length() const - { - return m_rep.length(); - } - - /** Returns the length of the string, excluding the 0-terminator. */ - uint size() const - { - return m_rep.length(); - } - - /** Returns a pointer to the contents of the string in the form of a 0-terminated C string */ - char *data() const - { - return m_rep.data(); - } - - /** Resizes the string to hold \a newlen characters - * (this value should include the 0-terminator). If the string is enlarged the contents will - * be left unmodified. - */ - bool resize( uint newlen ) - { - m_rep.resize(newlen); - return TRUE; - } - - /** Truncates the string at position \a pos. */ - bool truncate( uint pos ) - { - return resize(pos+1); - } - - /** Fills a string with a predefined character - * @param[in] c the character used to fill the string with. - * @param[in] len the number of character to fill. Use -1 to fill the whole string. - * @note the string will be resized to contain \a len characters. The contents of the - * string will be lost. - */ - bool fill( char c, int len = -1 ) - { - m_rep.fill(c,len); - return TRUE; - } - - /** Returns a deep copy of the string. */ - RCString copy() const - { - if (length()==0) return RCString(); - RCString cs(length()+1); - memcpy(cs.data(),data(),length()); - return cs; - } - - RCString &sprintf( const char *format, ... ); - int find( char c, int index=0, bool cs=TRUE ) const; - int find( const char *str, int index=0, bool cs=TRUE ) const; - int find( const RCString &str, int index=0, bool cs=TRUE ) const; - int find( const QRegExp &rx, int index=0 ) const; - int findRev( char c, int index=-1, bool cs=TRUE) const; - int findRev( const char *str, int index=-1, bool cs=TRUE) const; - int findRev( const QRegExp &rx, int index=-1 ) const; - int contains( char c, bool cs=TRUE ) const; - int contains( const char *str, bool cs=TRUE ) const; - int contains( const QRegExp &rx ) const; - bool stripPrefix(const char *prefix); - RCString left( uint len ) const; - RCString right( uint len ) const; - RCString mid( uint index, uint len=0xffffffff) const; - RCString lower() const; - RCString upper() const; - RCString stripWhiteSpace() const; - RCString simplifyWhiteSpace() const; - RCString &assign( const char *str ); - RCString &insert( uint index, const char *s ); - RCString &insert( uint index, char c); - RCString &append( const char *s ); - RCString &prepend( const char *s ); - RCString &remove( uint index, uint len ); - RCString &replace( uint index, uint len, const char *s); - RCString &replace( const QRegExp &rx, const char *str ); - short toShort( bool *ok=0 ) const; - ushort toUShort( bool *ok=0 ) const; - int toInt( bool *ok=0 ) const; - uint toUInt( bool *ok=0 ) const; - long toLong( bool *ok=0 ) const; - ulong toULong( bool *ok=0 ) const; - RCString &setNum(short n); - RCString &setNum(ushort n); - RCString &setNum(int n); - RCString &setNum(uint n); - RCString &setNum(long n); - RCString &setNum(ulong n); - - /** Converts the string to a plain C string */ - operator const char *() const - { - return (const char *)data(); - } - - /** Appends string \a str to this string and returns a reference to the result. */ - RCString &operator+=( const char *str ) - { - if (!str) return *this; - int len1 = length(); - int len2 = strlen(str); - resize(len1+len2+1); - memcpy(data()+len1,str,len2); - return *this; - } - - /** Appends character \a c to this string and returns a reference to the result. */ - RCString &operator+=( char c ) - { - int len = length(); - resize(len+2); - data()[len]=c; - return *this; - } - - /** Returns a reference to the character at index \a i. */ - char &at( uint i) const - { - return m_rep.at(i); - } - - /** Indexing operator. Equavalent to at(). */ - char &operator[]( int i ) const - { - return m_rep.at((uint)i); - } - - private: - - struct LSData; - - // long string representation - struct LongStringRep - { - uchar isShort : 1; // should be shared with ShortStringRep - uchar : 7; - LSData *d; - }; - -#define SHORT_STR_CAPACITY ((int)sizeof(LongStringRep)-1) -#define SHORT_STR_MAX_LEN (SHORT_STR_CAPACITY-1) - - - // short string representation - struct ShortStringRep - { - uchar isShort : 1; // should be shared with LongStringRep - uchar len : 7; - char str[SHORT_STR_CAPACITY]; // size including 0-terminator - }; - - // ref counting string header - struct LSHeader - { - int len; // length of string without 0 terminator - int refCount; // -1=leaked, 0=one ref & non-cost, n>0, n+1 refs, const - }; - // ref counting string data and methods - struct LSData : public LSHeader - { - char *toStr() - { - return (char*)(this+1); // string data starts after the header - } - - // creates a LSData item with room for size bytes (which includes the 0 terminator!) - // if size is zero, an empty string will be created. - static LSData *create(int size) - { - LSData *data; - data = (LSData*)malloc(sizeof(LSHeader)+size); - data->len = size-1; - data->refCount = 0; - data->toStr()[size-1] = 0; - return data; - } - // remove out reference to the data. Frees memory if no more users - void dispose() - { - if (--refCount<0) free(this); - } - - // resizes LSData so it can hold size bytes (which includes the 0 terminator!) - // if size is zero, the string will become empty - static LSData *resize(LSData *d,int size) - { - if (d->len>0 && d->refCount==0) // non-const, non-empty - { - d = (LSData*)realloc(d,sizeof(LSHeader)+size); - d->len = size-1; - d->toStr()[size-1] = 0; - return d; - } - else // need to make a copy - { - LSData *newData = LSData::create(size); - int len = d->len; - if (len>=size) len=size-1; - memcpy(newData->toStr(),d->toStr(),len); - newData->toStr()[len]=0; - d->dispose(); - return newData; - } - } - }; - - class StringRep - { - public: - StringRep() - { - //printf("%p:StringRep:empty construct\n",this); - u.s.isShort=TRUE; - u.s.len=0; - } - ~StringRep() - { - //printf("%p:StringRep:destruct(short=%d) str='%s'\n",this,u.s.isShort,data()); - if (!u.s.isShort) - { - u.l.d->dispose(); - } - } - StringRep(const StringRep &s) - { - if (&s!=this) - { - //printf("%p:StringRep:copy construct(short=%d)\n",this,s.u.s.isShort); - u = s.u; - if (!u.s.isShort) - { - u.l.d->refCount++; - } - } - } - StringRep(int size) - { - u.s.isShort = size<=SHORT_STR_CAPACITY; - //printf("%p:StringRep:size construct(size=%d,isShort=%d)\n",this,size,u.s.isShort); - if (u.s.isShort) // init short string - { - if (size>0) - { - u.s.len = size-1; - u.s.str[size-1]='\0'; - } - else - { - u.s.len = 0; - } - } - else // int long string - { - u.l.d = LSData::create(size); - } - } - StringRep(const char *str) - { - if (str) - { - int len = strlen(str); - u.s.isShort = len<=SHORT_STR_MAX_LEN; - //printf("%p:StringRep:c_str construct(isShort=%d,str='%s')\n",this,u.s.isShort,str); - if (u.s.isShort) - { - u.s.len = len; - memcpy(u.s.str,str,len+1); - } - else - { - u.l.d = LSData::create(len+1); - memcpy(u.l.d->toStr(),str,u.l.d->len); - } - } - else // create empty string - { - //printf("%p:StringRep:empty c_str construct\n",this); - u.s.isShort=TRUE; - u.s.len=0; - } - } - StringRep( const char *str, uint maxlen ) - { - if (str && maxlen>0) - { - uint len=strlen(str); - if (len>maxlen) len=maxlen; - u.s.isShort = len<=SHORT_STR_MAX_LEN; - //printf("%p:StringRep:c_str maxlen construct(isShort=%d)\n",this,u.s.isShort); - if (u.s.isShort) - { - u.s.len = len; - memcpy(u.s.str,str,len); - u.s.str[len]='\0'; - } - else - { - u.l.d = LSData::create(len+1); - memcpy(u.l.d->toStr(),str,len); - } - } - else // create empty string - { - //printf("%p:StringRep:empty c_str construct\n",this); - u.s.isShort=TRUE; - u.s.len=0; - } - } - StringRep &operator=(const StringRep &s) - { - if (!u.s.isShort) - { - u.l.d->dispose(); - } - if (s.u.s.isShort) // copy by value - { - //printf("%p:StringRep:operator=(short) s='%s'\n",this,s.data()); - u.s = s.u.s; - } - else // copy by reference - { - //printf("%p:StringRep:operator=(long) s='%s'\n",this,s.data()); - u.l.isShort=FALSE; - u.l.d = s.u.l.d; - u.l.d->refCount++; - } - return *this; - } - StringRep &operator=(const char *str) - { - if (!u.s.isShort) - { - u.l.d->dispose(); - } - if (str) - { - int len = strlen(str); - u.s.isShort = len<=SHORT_STR_MAX_LEN; - //printf("%p:StringRep:operator=(c_str) isShort=%d\n",this,u.s.isShort); - if (u.s.isShort) - { - u.s.len = len; - memcpy(u.s.str,str,len+1); - } - else - { - u.l.d = LSData::create(len+1); - memcpy(u.l.d->toStr(),str,u.l.d->len); - } - } - else - { - //printf("%p:StringRep:operator=(empty c_str)\n",this); - u.s.isShort=TRUE; - u.s.len=0; - } - return *this; - } - bool isEmpty() const - { - return u.s.isShort && u.s.len==0; - } - uint length() const - { - return u.s.isShort ? u.s.len : u.l.d->len; - } - char *data() const - { - if (u.s.isShort) - { - return u.s.len==0 ? 0 : (char*)u.s.str; - } - else - { - return u.l.d->len==0 ? 0 : u.l.d->toStr(); - } - } - char &at(int i) const - { - if (u.s.isShort) - { - return (char&)u.s.str[i]; - } - else - { - return u.l.d->toStr()[i]; - } - } - bool resize( uint newlen ) - { - if (u.s.isShort && newlen<=SHORT_STR_CAPACITY) // resize short string - { - if (newlen>0) - { - //printf("%p:StringRep:resize short2short\n",this); - u.s.len = newlen-1; - u.s.str[newlen-1]='\0'; - } - else - { - //printf("%p:StringRep:resize short2empty\n",this); - u.s.len = 0; - } - } - else if (u.s.isShort) // turn short string into long string - { - //printf("%p:StringRep:resize short2long\n",this); - StringRep tmp = *this; - u.s.isShort=FALSE; - u.l.d = LSData::create(newlen); - if (tmp.u.s.len>0) - { - memcpy(u.l.d->toStr(),tmp.u.s.str,tmp.u.s.len+1); - } - else - { - u.l.d->toStr()[0]='\0'; - } - } - else if (!u.s.isShort && newlen<=SHORT_STR_CAPACITY) // turn long string into short string - { - if (newlen>0) - { - //printf("%p:StringRep:resize long2short\n",this); - StringRep tmp(newlen); // copy short part into tmp buffer - memcpy(tmp.u.s.str,u.l.d->toStr(),newlen-1); - tmp.u.s.str[newlen-1]='\0'; - u.l.d->dispose(); - u.s = tmp.u.s; - } - else - { - //printf("%p:StringRep:resize long2empty\n",this); - u.l.d->dispose(); - u.s.isShort=TRUE; - u.s.len=0; - } - } - else // resize long string - { - //printf("%p:StringRep:resize long2long\n",this); - u.l.d = u.l.d->resize(u.l.d,newlen); - } - return TRUE; - } - bool fill( char c, int len ) - { - if (len<0) len=length(); - if (len!=(int)length()) - { - if (len>0) - { - resize(len+1); - } - else - { - if (!u.s.isShort) - { - u.l.d->dispose(); - } - u.s.isShort=TRUE; - u.s.len=0; - } - } - if (len>0) - { - memset(data(),c,len); - } - return TRUE; - } - private: - union - { - ShortStringRep s; - LongStringRep l; - } u; - }; - StringRep m_rep; -}; - -/***************************************************************************** - QCString stream functions - *****************************************************************************/ -#ifndef QT_NO_DATASTREAM -Q_EXPORT QDataStream &operator<<( QDataStream &, const QCString & ); -Q_EXPORT QDataStream &operator>>( QDataStream &, QCString & ); -#endif - -/***************************************************************************** - RCString non-member operators - *****************************************************************************/ - -Q_EXPORT inline bool operator==( const RCString &s1, const RCString &s2 ) -{ return qstrcmp(s1.data(),s2.data()) == 0; } - -Q_EXPORT inline bool operator==( const RCString &s1, const char *s2 ) -{ return qstrcmp(s1.data(),s2) == 0; } - -Q_EXPORT inline bool operator==( const char *s1, const RCString &s2 ) -{ return qstrcmp(s1,s2.data()) == 0; } - -Q_EXPORT inline bool operator!=( const RCString &s1, const RCString &s2 ) -{ return qstrcmp(s1.data(),s2.data()) != 0; } - -Q_EXPORT inline bool operator!=( const RCString &s1, const char *s2 ) -{ return qstrcmp(s1.data(),s2) != 0; } - -Q_EXPORT inline bool operator!=( const char *s1, const RCString &s2 ) -{ return qstrcmp(s1,s2.data()) != 0; } - -Q_EXPORT inline bool operator<( const RCString &s1, const RCString& s2 ) -{ return qstrcmp(s1.data(),s2.data()) < 0; } - -Q_EXPORT inline bool operator<( const RCString &s1, const char *s2 ) -{ return qstrcmp(s1.data(),s2) < 0; } - -Q_EXPORT inline bool operator<( const char *s1, const RCString &s2 ) -{ return qstrcmp(s1,s2.data()) < 0; } - -Q_EXPORT inline bool operator<=( const RCString &s1, const char *s2 ) -{ return qstrcmp(s1.data(),s2) <= 0; } - -Q_EXPORT inline bool operator<=( const char *s1, const RCString &s2 ) -{ return qstrcmp(s1,s2.data()) <= 0; } - -Q_EXPORT inline bool operator>( const RCString &s1, const char *s2 ) -{ return qstrcmp(s1.data(),s2) > 0; } - -Q_EXPORT inline bool operator>( const char *s1, const RCString &s2 ) -{ return qstrcmp(s1,s2.data()) > 0; } - -Q_EXPORT inline bool operator>=( const RCString &s1, const char *s2 ) -{ return qstrcmp(s1.data(),s2) >= 0; } - -Q_EXPORT inline bool operator>=( const char *s1, const RCString &s2 ) -{ return qstrcmp(s1,s2.data()) >= 0; } - -Q_EXPORT inline RCString operator+( const RCString &s1, const RCString &s2 ) -{ - RCString tmp(s1); - tmp += s2; - return tmp; -} - - -inline RCString operator+( const RCString &s1, const QGString &s2 ); -inline RCString operator+( const QGString &s1, const RCString &s2 ); - - -Q_EXPORT inline RCString operator+( const RCString &s1, const char *s2 ) -{ - RCString tmp(s1); - tmp += s2; - return tmp; -} - -Q_EXPORT inline RCString operator+( const char *s1, const RCString &s2 ) -{ - RCString tmp(s1); - tmp += s2; - return tmp; -} - -Q_EXPORT inline RCString operator+( const RCString &s1, char c2 ) -{ - RCString tmp( s1.data() ); - tmp += c2; - return tmp; -} - -Q_EXPORT inline RCString operator+( char c1, const RCString &s2 ) -{ - RCString tmp; - tmp += c1; - tmp += s2; - return tmp; -} - -inline const char *qPrint(const char *s) -{ - if (s) return s; else return ""; -} - -inline const char *qPrint(const RCString &s) -{ - if (!s.isEmpty()) return s.data(); else return ""; -} - - -#endif - |