/* 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. */ #include #ifdef HAVE_STDINT_H #include #endif #include #include #include #include "atomicstring.h" class AtomicString::Data: public TQString { public: uint refcount; Data(): refcount( 0 ) { } Data( const TQString &s ): TQString( s ), refcount( 0 ) { } }; AtomicString::AtomicString(): m_string( 0 ) { } AtomicString::AtomicString( const AtomicString &other ) { s_storeMutex.lock(); m_string = other.m_string; ref( m_string ); s_storeMutex.unlock(); } AtomicString::AtomicString( const TQString &string ): m_string( 0 ) { if( string.isEmpty() ) return; Data *s = new Data( string ); // note: s is a shallow copy s_storeMutex.lock(); m_string = static_cast( *( s_store.insert( s ).first ) ); ref( m_string ); uint rc = s->refcount; if( rc && !isMainThread()) { // Inserted, and we are not in the main thread -- we need to make s a deep copy, // as this copy may be refcounted by the main thread outside our locks (TQString &) (*s) = TQDeepCopy( string ); } s_storeMutex.unlock(); if ( !rc ) delete( s ); // already present } AtomicString::~AtomicString() { s_storeMutex.lock(); deref( m_string ); s_storeMutex.unlock(); } TQString AtomicString::string() const { if ( !m_string ) return TQString(); // References to the stored string are only allowed to circulate in the main thread if ( isMainThread() ) return *m_string; else return deepCopy(); } TQString AtomicString::deepCopy() const { if (m_string) return TQString( m_string->unicode(), m_string->length() ); return TQString(); } bool AtomicString::isEmpty() const { return !m_string; } const TQString *AtomicString::ptr() const { if( m_string ) return m_string; return &null_tqstring; } uint AtomicString::refcount() const { if ( m_string ) { s_storeMutex.lock(); uint rc = m_string->refcount; s_storeMutex.unlock(); return rc; } return 0; } AtomicString &AtomicString::operator=( const AtomicString &other ) { if( m_string == other.m_string ) return *this; s_storeMutex.lock(); deref( m_string ); m_string = other.m_string; ref( m_string ); s_storeMutex.unlock(); return *this; } // needs to be called holding the lock inline void AtomicString::deref( Data *s ) { checkLazyDeletes(); // a good time to do this if( !s ) return; if( !( --s->refcount ) ) { s_store.erase( s ); // only the main thread is allowed to delete stored strings if ( isMainThread() ) delete s; else s_lazyDeletes.append(s); } } // needs to be called holding the lock inline void AtomicString::ref( Data *s ) { checkLazyDeletes(); // a good time to do this if( s ) s->refcount++; } // It is not necessary to hold the store mutex here. bool AtomicString::isMainThread() { // For isMainThread(), we could use TQThread::currentThread(), except the // docs say it's unreliable. And in general TQThreads don't like to be called from // app destructors. Good old pthreads will serve us well. As for Windows, these // two calls surely have equivalents; better yet we'll have QT4 and thread safe // TQStrings by then. // Note that the the static local init is thread safe. static pthread_t main_thread = pthread_self(); return pthread_equal(pthread_self(), main_thread); } // call holding the store mutex inline void AtomicString::checkLazyDeletes() { // only the main thread is allowed to delete if ( isMainThread() ) { s_lazyDeletes.setAutoDelete(true); s_lazyDeletes.clear(); } } AtomicString::set_type AtomicString::s_store; TQPtrList AtomicString::s_lazyDeletes; TQMutex AtomicString::s_storeMutex;