/* Copyright (c) 2006 Gábor Lehel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * A thin wrapper over TQString which ensures only a single copy of string data * is stored for equivalent strings. As a side benefit, testing for equality * is reduced to a pointer comparison. Construction is slower than a TQString, * as it must be checked for equality with existing strings. (A hash set is * used for this purpose. According to benchmarks, Paul Hsieh's SuperFastHash * (which is currently used -- see http://www.azillionmonkeys.com/qed/hash.html) * can hash 5 million 256 byte strings in 1.34s on a 1.62GHz Athlon XP.) For * other use, the overhead compared to a plain TQString should be minimal. * * Added note: due to TQString's thread unsafe refcounting, special precautions have to be * taken to avoid memory corruption, while still maintaining some level of efficiency. * We deepCopy strings, unless we are in the same thread that *first* used * AtomicStrings. Also, deletions from other threads are delayed until that first thread * calls AtomicString again. Thus, we would appear to leak memory if many AtomicStrings * are deleted in a different thread than the main thread, and the main thread would * never call AtomicString again. But this is unlikely since the GUI thread is the one * manipulating AtomicStrings mostly. You can call the static method * AtomicString::isMainString first thing in the app to make sure the GUI thread is * identified correctly. This workaround can be removed with QT4. * * @author Gábor Lehel */ #ifndef AMAROK_ATOMICSTRING_H #define AMAROK_ATOMICSTRING_H #include "config.h" #include #include "amarok_export.h" #include #include #include class LIBAMAROK_EXPORT AtomicString { public: /** * Constructs an empty string. * @see isEmpty */ AtomicString(); /** * Constructs a copy of \p string. This operation takes constant time. * @param string the string to copy * @see operator= */ AtomicString( const AtomicString &other ); /** * Constructs a copy of \p string. * @param string the string to copy */ AtomicString( const TQString &string ); /** * Destroys the string. * Note: this isn't virtual, to halve sizeof(). */ ~AtomicString(); /** * Makes this string a copy of \p string. This operation takes constant time. * @param string the string to copy */ AtomicString &operator=( const AtomicString &other ); /** * This operation takes constant time. * @return whether this string and \p string are equivalent */ bool operator==( const AtomicString &other ) const { return m_string == other.m_string; } bool operator<( const AtomicString &other ) const { return m_string < other.m_string; } // bool operator!=( const AtomicString &other ) const { return m_string != other.m_string; } /** * Returns a reference to this string, avoiding copies if possible. * * @return the string. */ TQString string() const; /** * Implicitly casts to a TQString. * @return the string */ inline operator TQString() const { return string(); } /** * Useful for threading. * @return a deep copy of the string */ TQString deepCopy() const; /** * For convenience. Equivalent to isNull(). * @return whether the string is empty * @see isNull */ bool isEmpty() const; /** * For convenience. Equivalent to isEmpty(). * @return whether the string is empty * @see isEmpty */ inline bool isNull() const { return isEmpty(); } /** * Returns the internal pointer to the string. * Guaranteed to be equivalent for equivalent strings, and different for * different ones. This can be useful for certain kinds of hacks, but * shouldn't normally be used. * * Note: DO NOT COPY this pointer with TQString() or TQString=. It is not * thread safe to do it (TQString internal refcount) * @return the internal pointer to the string */ const TQString *ptr() const; /** * For convenience, so you can do atomicstring->TQStringfunction(), * instead of atomicstring.string().TQStringfunction(). The same warning * applies as for the above ptr() function. */ inline const TQString *operator->() const { return ptr(); } /** * For debugging purposes. * @return the number of nonempty AtomicStrings equivalent to this one */ uint refcount() const; /** * If called first thing in the app, this makes sure that AtomicString optimizes * string usage for the main thread. * @return true if this thread is considered the "main thread". */ static bool isMainThread(); private: struct less { bool operator()( const TQString *a, const TQString *b ) const { return *a < *b; } }; typedef std::set set_type; class Data; friend class Data; void ref( Data* ); void deref( Data* ); static void checkLazyDeletes(); Data *m_string; TQString null_tqstring; // static data static set_type s_store; // main string store static TQPtrList s_lazyDeletes; // strings scheduled for deletion // by main thread static TQMutex s_storeMutex; // protects the static data above }; #endif