/*************************************************************************** copyright : (C) 2006 by David Nolden email : david.nolden.kdevelop@art-master.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef __SIMPLETYPECACHEBINDER_H__ #define __SIMPLETYPECACHEBINDER_H__ #include "simpletypenamespace.h" ///In case the hashing-stuff brings some regressions, it can be removed again using this switch. #include #include //#define TEST_REMAP template class SimpleTypeCacheBinder : public Base { public: SimpleTypeCacheBinder( SimpleTypeCacheBinder* b ) : Base( b ), m_locateCache( b->m_locateCache ), m_memberCache( b->m_memberCache ), m_basesCache( b->m_basesCache ), secondaryActive( b->secondaryActive ), m_classListCache( b->m_classListCache ), primaryActive( b->primaryActive ), m_haveBasesCache( b->m_haveBasesCache ) {} SimpleTypeCacheBinder() : Base(), m_haveBasesCache( false ), secondaryActive( true ), primaryActive( true ) {} template SimpleTypeCacheBinder( InitType t ) : Base ( t ), m_haveBasesCache( false ) , secondaryActive( true ), primaryActive( true ) {} template SimpleTypeCacheBinder( InitType1 t, InitType2 t2 ) : Base ( t, t2 ), m_haveBasesCache( false ), secondaryActive( true ), primaryActive( true ) {} using typename Base::LocateMode; struct LocateDesc { TypeDesc mname; //TQString fullName; SimpleTypeImpl::LocateMode mmode; int mdir; SimpleTypeImpl::MemberInfo::MemberType mtypeMask; size_t m_hashKey; LocateDesc() {} LocateDesc( const TypeDesc& name, SimpleTypeImpl::LocateMode mode, int dir, SimpleTypeImpl::MemberInfo::MemberType typeMask ) : mname( name ), mmode( mode ) , mdir( dir ) , mtypeMask( typeMask ), m_hashKey( name.hashKey() + 11*int(mode) + 13*dir + 17*int(typeMask) ) { //fullName = mname.fullNameChain();//fullTypeStructure(); } ///@todo this should use hashing too int compare( const LocateDesc& rhs ) const { if ( m_hashKey != rhs.m_hashKey ) { if ( m_hashKey < rhs.m_hashKey ) return -1; else return 1; } if ( mname.hashKey2() != rhs.mname.hashKey2() ) { if ( mname.hashKey2() < rhs.mname.hashKey2() ) return -1; else return 1; } if ( mmode != rhs.mmode ) { if ( mmode < rhs.mmode ) return -1; else return 1; } if ( mdir != rhs.mdir ) { if ( mdir < rhs.mdir ) return -1; else return 1; } if ( mtypeMask != rhs.mtypeMask ) { if ( mtypeMask < rhs.mtypeMask ) return -1; else return 1; } return 0; } bool operator < ( const LocateDesc& rhs ) const { return compare( rhs ) == -1; } bool operator == ( const LocateDesc& rhs ) const { //return compare( rhs ) == 0; if( m_hashKey == rhs.m_hashKey && mname.hashKey2() == rhs.mname.hashKey2() ) return mname.name() == rhs.mname.name(); else return false; } bool operator > ( const LocateDesc& rhs ) const { return compare( rhs ) == 1; } inline size_t hashKey() const { return m_hashKey; } struct hash { inline size_t operator () ( const LocateDesc& m ) const { return m.hashKey(); } }; }; struct MemberFindDesc { TypeDesc m_desc; TQString fullName; SimpleTypeImpl::MemberInfo::MemberType findType; size_t m_hashKey; //in time check why it is necessary to cache this key size_t m_hashKey2; MemberFindDesc() : m_hashKey( 0 ) {} MemberFindDesc( TypeDesc d, SimpleTypeImpl::MemberInfo::MemberType ft ) : m_desc( d ), findType( ft ), m_hashKey( d.hashKey() + findType ), m_hashKey2( d.hashKey2() + findType ) { //m_desc.makePrivate(); } int compare( const MemberFindDesc& rhs ) const { if ( fullName.isEmpty() ) const_cast(this)->fullName = m_desc.fullNameChain(); if ( rhs.fullName.isEmpty() ) const_cast(&rhs)->fullName = rhs.m_desc.fullNameChain(); const TQString& a = fullName; //m_desc.fullNameChain(); const TQString& b = rhs.fullName; //m_desc.fullNameChain(); if ( a != b ) { if ( a < b ) return -1; else return 1; } if ( findType != rhs.findType ) { if ( findType < rhs.findType ) return -1; else return 1; } return 0; } bool operator < ( const MemberFindDesc& rhs ) const { return compare( rhs ) == -1; } //#endif inline size_t hashKey() const { return m_hashKey; } bool operator == ( const MemberFindDesc& rhs ) const { bool ret = m_hashKey2 == rhs.m_hashKey2 && findType == rhs.findType; if( ret ) return m_desc.name() == rhs.m_desc.name(); //Just for a little more security return ret; } /* bool operator > ( const MemberFindDesc& rhs ) const { return compare( rhs ) == 1; }*/ struct hash { inline size_t operator () ( const MemberFindDesc& m ) const { return m.hashKey(); } }; }; typedef __gnu_cxx::hash_map LocateMap; typedef __gnu_cxx::hash_map MemberMap; typedef __gnu_cxx::hash_map, typename MemberFindDesc::hash > ClassListMap; virtual SimpleTypeImpl::MemberInfo findMember( TypeDesc name, SimpleTypeImpl::MemberInfo::MemberType type ) { if ( !primaryActive ) return Base::findMember( name, type ); MemberFindDesc key( name, type ); typename MemberMap::iterator it = m_memberCache.find( key ); if ( it != m_memberCache.end() ) { ifVerbose( dbg() << "\"" << Base::str() << "\" took member-info for \"" << name.fullNameChain() << "\" from the cache: " << (*it).second.name << endl ); return (*it).second; } else { SimpleTypeImpl::MemberInfo mem; m_memberCache.insert( std::make_pair( key, mem ) ); //This is done to prevent expensive endless recursion mem = Base::findMember( name, type ); std::pair< typename MemberMap::iterator, bool > r = m_memberCache.insert( std::make_pair( key, mem ) ); if ( !r.second ) { (*r.first).second = mem; } #ifdef TEST_REMAP typename MemberMap::iterator it = m_memberCache.find( key ); if ( it == m_memberCache.end() ) dbgMajor() << "\"" << Base::str() << "\"remap failed with \"" << name.fullNameChain() << "\"" << endl; #endif return mem; } } virtual TQValueList getMemberClasses( const TypeDesc& name ) { if ( !primaryActive ) return Base::getMemberClasses( name ); MemberFindDesc key( name, Base::MemberInfo::NestedType ); typename ClassListMap::iterator it = m_classListCache.find( key ); if ( it != m_classListCache.end() ) { /*ifVerbose( dbg() << "\"" << Base::str() << "\" took member-info for \"" << name.fullNameChain() << "\" from the cache: " << (*it).second. << endl );*/ return (*it).second; } else { TQValueList mem; m_classListCache.insert( std::make_pair( key, mem ) ); mem = Base::getMemberClasses( name ); std::pair r = m_classListCache.insert( std::make_pair( key, mem ) ); if ( !r.second ) (*r.first).second = mem; #ifdef TEST_REMAP typename ClassListMap::iterator it = m_classListCache.find( key ); if ( it == m_classListCache.end() ) dbgMajor() << "\"" << Base::str() << "\"remap failed with \"" << name.fullNameChain() << "\"" << endl; #endif return mem; } } virtual LocateResult locateType( TypeDesc name , SimpleTypeImpl::LocateMode mode, int dir, SimpleTypeImpl::MemberInfo::MemberType typeMask ) { if ( !secondaryActive ) return Base::locateType( name, mode, dir, typeMask ); LocateDesc desc( name, mode, dir, typeMask ); typename LocateMap::iterator it = m_locateCache.find( desc ); if ( it != m_locateCache.end() ) { Debug d( "#lo#" ); ifVerbose( dbg() << "\"" << Base::str() << "\" located \"" << name.fullNameChain() << "\" from the cache" << endl ); return (*it).second; } else { LocateResult t; m_locateCache.insert( std::make_pair( desc, t ) ); //Done to prevent expensive recursion. t = Base::locateType( name, mode, dir, typeMask ); std::pair< typename LocateMap::iterator, bool > r = m_locateCache.insert( std::make_pair( desc, t ) ); if ( !r.second ) (*r.first).second = t; #ifdef TEST_REMAP typename LocateMap::iterator it = m_locateCache.find( desc ); if ( it == m_locateCache.end() ) dbgMajor() << "\"" << Base::str() << "\"remap failed with \"" << name.fullNameChain() << "\"" << endl; #endif return t; } } virtual TQValueList getBases() { ///@todo this needs a lookup for different includeFiles.. if ( m_haveBasesCache ) { ifVerbose( dbg() << "\"" << Base::str() << "\" took base-info from the cache" << endl ); return m_basesCache; } else { m_basesCache = Base::getBases(); m_haveBasesCache = true; return m_basesCache; } } private: LocateMap m_locateCache; MemberMap m_memberCache; ClassListMap m_classListCache; TQValueList m_basesCache; bool m_haveBasesCache; bool secondaryActive, primaryActive; protected: virtual typename Base::TypePointer clone() { return new SimpleTypeCacheBinder( this ); } virtual void invalidatePrimaryCache( bool onlyNegative ) { //if( !m_memberCache.isEmpty() ) dbg() << "\"" << Base::str() << "\" primary caches cleared" << endl; if ( !onlyNegative) m_memberCache.clear(); else { for ( typename MemberMap::iterator it = m_memberCache.begin(); it != m_memberCache.end(); ) { if ( (*it).second.memberType == SimpleTypeImpl::MemberInfo::NotFound ) m_memberCache.erase( it++ ); else ++it; } } m_classListCache.clear(); } virtual void invalidateSecondaryCache() { //if( !m_locateCache.isEmpty() ) dbg() << "\"" << Base::str() << "\" secondary caches cleared" << endl; m_locateCache.clear(); m_haveBasesCache = false; m_basesCache.clear(); } virtual void setSecondaryCacheActive( bool active ) { secondaryActive = active; } virtual void setPrimaryCacheActive( bool active ) { primaryActive = active; } virtual void invalidateCache() { invalidatePrimaryCache( false ); invalidateSecondaryCache(); }; }; //typedef SimpleTypeCacheBinder SimpleTypeImpl; class SimpleTypeCodeModel; class SimpleTypeCatalog; class SimpleTypeNamespace; class SimpleTypeCodeModelFunction; class SimpleTypeCatalogFunction; typedef SimpleTypeCacheBinder SimpleTypeCachedCodeModel; typedef SimpleTypeCacheBinder SimpleTypeCachedCatalog; typedef SimpleTypeCacheBinder SimpleTypeCachedNamespace; typedef SimpleTypeCacheBinder SimpleTypeCachedCodeModelFunction; typedef SimpleTypeCacheBinder SimpleTypeCachedCatalogFunction; #endif