Lunchbox  1.4.0
perThreadRef.h
00001 
00002 /* Copyright (c) 2008-2012, Stefan Eilemann <eile@equalizergraphics.com> 
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #ifndef LUNCHBOX_PERTHREADREF_H
00019 #define LUNCHBOX_PERTHREADREF_H
00020 
00021 #include <lunchbox/debug.h>
00022 #include <lunchbox/refPtr.h>
00023 
00024 namespace lunchbox
00025 {
00026 namespace detail { class PerThreadRef; }
00027 
00036     template< typename T > class PerThreadRef : public NonCopyable
00037     {
00038     public:
00040         PerThreadRef();
00042         ~PerThreadRef();
00043 
00045         PerThreadRef<T>& operator = ( RefPtr< T > data );
00046 
00048         PerThreadRef<T>& operator = ( const PerThreadRef<T>& rhs );
00049 
00051         RefPtr< const T > get() const;
00053         RefPtr< T > get();
00054 
00059         T* getPointer();
00060 
00065         T* operator->();
00066 
00071         const T* operator->() const;
00072 
00077         bool operator == ( const PerThreadRef& rhs ) const 
00078             { return ( get() == rhs.get( )); }
00079 
00084         bool operator == ( const RefPtr< T >& rhs ) const
00085             { return ( get()==rhs ); }
00086 
00091         bool operator != ( const RefPtr< T >& rhs ) const
00092             { return ( get()!=rhs ); }
00093 
00098         bool operator ! () const;
00099 
00104         bool isValid() const;
00105 
00106     private:
00107         PerThreadRef* const _impl;
00108     };
00109 
00110 
00111 //----------------------------------------------------------------------
00112 // implementation
00113 //----------------------------------------------------------------------
00114 
00115 // Crude test if pthread.h was included
00116 #ifdef PTHREAD_MUTEX_INITIALIZER
00117 #  ifndef HAVE_PTHREAD_H
00118 #    define HAVE_PTHREAD_H
00119 #  endif
00120 #endif
00121 
00122 #ifdef HAVE_PTHREAD_H
00123 namespace detail
00124 {
00125 class PerThreadRef
00126 {
00127 public:
00128     pthread_key_t key;
00129 };
00130 }
00131 
00132 template< typename T >
00133 PerThreadRef<T>::PerThreadRef() 
00134         : _impl( new detail::PerThreadRef )
00135 {
00136     const int error = pthread_key_create( &_impl->key, 0 );
00137     if( error )
00138     {
00139         LBERROR << "Can't create thread-specific key: " 
00140                 << strerror( error ) << std::endl;
00141         LBASSERT( !error );
00142     }
00143 }
00144 
00145 template< typename T >
00146 PerThreadRef<T>::~PerThreadRef()
00147 {
00148     RefPtr< T > object = get();
00149 
00150     pthread_key_delete( _impl->key );
00151     delete _impl;
00152 
00153     object.unref();
00154 }
00155 
00156 template< typename T >
00157 PerThreadRef<T>& PerThreadRef<T>::operator = ( RefPtr< T > data )
00158 { 
00159     data.ref(); // ref new
00160 
00161     RefPtr< T > object = get();
00162     pthread_setspecific( _impl->key, static_cast<const void*>( data.get( )));
00163 
00164     object.unref(); // unref old
00165     return *this; 
00166 }
00167 
00168 template< typename T >
00169 PerThreadRef<T>& PerThreadRef<T>::operator = ( const PerThreadRef<T>& rhs )
00170 {
00171     RefPtr< T > newObject = rhs.get();
00172     newObject.ref(); // ref new
00173 
00174     RefPtr< T > object = get();
00175     pthread_setspecific( _impl->key, pthread_getspecific( rhs._impl->key ));
00176 
00177     object.unref(); // unref old
00178     return *this;
00179 }
00180 
00181 template< typename T >
00182 RefPtr< const T > PerThreadRef<T>::get() const
00183 {
00184     return static_cast< const T* >( pthread_getspecific( _impl->key )); 
00185 }
00186 
00187 template< typename T >
00188 RefPtr< T > PerThreadRef<T>::get()
00189 {
00190     return static_cast< T* >( pthread_getspecific( _impl->key )); 
00191 }
00192 
00193 template< typename T >
00194 T* PerThreadRef<T>::getPointer()
00195 {
00196     return static_cast< T* >( pthread_getspecific( _impl->key )); 
00197 }
00198 
00199 template< typename T >
00200 T* PerThreadRef<T>::operator->() 
00201 {
00202     LBASSERT( pthread_getspecific( _impl->key ));
00203     return static_cast< T* >( pthread_getspecific( _impl->key )); 
00204 }
00205 
00206 template< typename T >
00207 const T* PerThreadRef<T>::operator->() const 
00208 { 
00209     LBASSERT( pthread_getspecific( _impl->key ));
00210     return static_cast< const T* >( pthread_getspecific( _impl->key )); 
00211 }
00212 
00213 template< typename T >
00214 bool PerThreadRef<T>::operator ! () const
00215 {
00216     return pthread_getspecific( _impl->key ) == 0;
00217 }
00218 
00219 template< typename T >
00220 bool PerThreadRef<T>::isValid() const
00221 {
00222     return pthread_getspecific( _impl->key ) != 0;
00223 }
00224 #endif // HAVE_PTHREAD_H
00225 
00226 }
00227 #endif //LUNCHBOX_PERTHREADREF_H