Speed up Altium compound file reader

Just read the footprint list once and store the cache for later use.
This commit is contained in:
Seth Hillbrand 2023-08-31 09:16:35 -07:00
parent b8b2498e0c
commit 1b63d11adf
4 changed files with 70 additions and 148 deletions

View File

@ -89,159 +89,27 @@ ALTIUM_COMPOUND_FILE::ALTIUM_COMPOUND_FILE( const wxString& aFilePath )
}
std::map<wxString, wxString> ALTIUM_COMPOUND_FILE::ListLibFootprints() const
std::map<wxString, wxString> ALTIUM_COMPOUND_FILE::ListLibFootprints()
{
std::map<wxString, wxString> patternMap;
if( m_libFootprintDirNameCache.empty() )
cacheLibFootprintNames();
if( !m_reader )
return patternMap;
const CFB::COMPOUND_FILE_ENTRY* root = m_reader->GetRootEntry();
if( !root )
return patternMap;
m_reader->EnumFiles( root, 2,
[&]( const CFB::COMPOUND_FILE_ENTRY* entry, const CFB::utf16string& dir,
int level ) -> int
{
std::wstring dirName = UTF16ToWstring( dir.data(), dir.size() );
std::wstring fileName = UTF16ToWstring( entry->name, entry->nameLen );
if( m_reader->IsStream( entry ) && fileName == L"Parameters" )
{
ALTIUM_PARSER parametersReader( *this, entry );
std::map<wxString, wxString> parameterProperties =
parametersReader.ReadProperties();
wxString key = ALTIUM_PARSER::ReadString(
parameterProperties, wxT( "PATTERN" ), wxT( "" ) );
wxString fpName = ALTIUM_PARSER::ReadUnicodeString(
parameterProperties, wxT( "PATTERN" ), wxT( "" ) );
patternMap.emplace( key, fpName );
}
return 0;
} );
return patternMap;
return m_libFootprintDirNameCache;
}
std::tuple<wxString, const CFB::COMPOUND_FILE_ENTRY*>
ALTIUM_COMPOUND_FILE::FindLibFootprintDirName( const wxString& aFpUnicodeName ) const
ALTIUM_COMPOUND_FILE::FindLibFootprintDirName( const wxString& aFpUnicodeName )
{
if( !m_reader )
return std::tuple<wxString, const CFB::COMPOUND_FILE_ENTRY*>( wxEmptyString, nullptr );
if( m_libFootprintNameCache.empty() )
cacheLibFootprintNames();
const CFB::COMPOUND_FILE_ENTRY* root = m_reader->GetRootEntry();
auto it = m_libFootprintNameCache.find( aFpUnicodeName );
if( !root )
return std::tuple<wxString, const CFB::COMPOUND_FILE_ENTRY*>( wxEmptyString, nullptr );
if( it == m_libFootprintNameCache.end() )
return { wxEmptyString, nullptr };
wxString retStr;
const CFB::COMPOUND_FILE_ENTRY* retEntry = nullptr;
// Cheap and easy check first as most ASCII-coded libs are under the same dir name
m_reader->EnumFiles( root, 1,
[&]( const CFB::COMPOUND_FILE_ENTRY* tentry, const CFB::utf16string&, int ) -> int
{
// We are only looking for one string, so if we found it, break the loop
if( retStr != wxEmptyString )
return 1;
std::wstring dirName = UTF16ToWstring( tentry->name, tentry->nameLen );
if( aFpUnicodeName.ToStdWstring().compare( 0, 10, dirName, 0, 10 ) )
return 0;
m_reader->EnumFiles( tentry, 1,
[&]( const CFB::COMPOUND_FILE_ENTRY* entry, const CFB::utf16string&, int ) -> int
{
std::wstring fileName = UTF16ToWstring( entry->name, entry->nameLen );
if( m_reader->IsStream( entry ) && fileName == L"Parameters" )
{
ALTIUM_PARSER parametersReader( *this, entry );
std::map<wxString, wxString> parameterProperties =
parametersReader.ReadProperties();
wxString fpName = ALTIUM_PARSER::ReadUnicodeString(
parameterProperties, wxT( "PATTERN" ), wxT( "" ) );
if( fpName == aFpUnicodeName )
{
retStr = dirName;
return 1;
}
}
return 0;
} );
if( retStr != wxEmptyString )
{
retEntry = tentry;
return 1;
}
return 0;
} );
if( retStr != wxEmptyString )
return std::make_tuple( retStr, retEntry );
// Now do the expensive check, iterating through each directory in the library and reading the files
m_reader->EnumFiles( root, 1,
[&]( const CFB::COMPOUND_FILE_ENTRY* tentry, const CFB::utf16string& dir,
int level ) -> int
{
if( retStr != wxEmptyString )
return 1;
std::wstring dirName = UTF16ToWstring( tentry->name, tentry->nameLen );
m_reader->EnumFiles( tentry, 1,
[&]( const CFB::COMPOUND_FILE_ENTRY* entry, const CFB::utf16string&, int ) -> int
{
std::wstring fileName = UTF16ToWstring( entry->name, entry->nameLen );
if( m_reader->IsStream( entry ) && fileName == L"Parameters" )
{
ALTIUM_PARSER parametersReader( *this, entry );
std::map<wxString, wxString> parameterProperties =
parametersReader.ReadProperties();
wxString fpName = ALTIUM_PARSER::ReadUnicodeString(
parameterProperties, wxT( "PATTERN" ), wxT( "" ) );
if( fpName == aFpUnicodeName )
{
retStr = dirName;
return 1;
}
}
return 0;
} );
if( retStr != wxEmptyString )
{
retEntry = tentry;
return 1;
}
return 0;
} );
if( retStr != wxEmptyString )
return std::make_tuple( retStr, retEntry );
return std::tuple<wxString, const CFB::COMPOUND_FILE_ENTRY*>( wxEmptyString, nullptr );
return { it->first, it->second };
}
@ -351,6 +219,53 @@ ALTIUM_COMPOUND_FILE::FindStream( const std::vector<std::string>& aStreamPath )
}
void ALTIUM_COMPOUND_FILE::cacheLibFootprintNames()
{
m_libFootprintDirNameCache.clear();
m_libFootprintNameCache.clear();
if( !m_reader )
return;
const CFB::COMPOUND_FILE_ENTRY* root = m_reader->GetRootEntry();
if( !root )
return;
m_reader->EnumFiles( root, 1,
[this]( const CFB::COMPOUND_FILE_ENTRY* tentry, const CFB::utf16string& dir,
int level ) -> int
{
if( m_reader->IsStream( tentry ) )
return 0;
m_reader->EnumFiles( tentry, 1,
[&]( const CFB::COMPOUND_FILE_ENTRY* entry, const CFB::utf16string&, int ) -> int
{
std::wstring fileName = UTF16ToWstring( entry->name, entry->nameLen );
if( m_reader->IsStream( entry ) && fileName == L"Parameters" )
{
ALTIUM_PARSER parametersReader( *this, entry );
std::map<wxString, wxString> parameterProperties =
parametersReader.ReadProperties();
wxString key = ALTIUM_PARSER::ReadString(
parameterProperties, wxT( "PATTERN" ), wxT( "" ) );
wxString fpName = ALTIUM_PARSER::ReadUnicodeString(
parameterProperties, wxT( "PATTERN" ), wxT( "" ) );
m_libFootprintDirNameCache[key] = fpName;
m_libFootprintNameCache[fpName] = tentry;
}
return 0;
} );
return 0;
} );
}
ALTIUM_PARSER::ALTIUM_PARSER( const ALTIUM_COMPOUND_FILE& aFile,
const CFB::COMPOUND_FILE_ENTRY* aEntry )
{
@ -588,3 +503,4 @@ wxString ALTIUM_PARSER::ReadUnicodeString( const std::map<wxString, wxString>& a
return ReadString( aProps, aKey, aDefault );
}

View File

@ -67,9 +67,9 @@ public:
const CFB::CompoundFileReader& GetCompoundFileReader() const { return *m_reader; }
std::map<wxString, wxString> ListLibFootprints() const;
std::map<wxString, wxString> ListLibFootprints();
std::tuple<wxString, const CFB::COMPOUND_FILE_ENTRY*> FindLibFootprintDirName( const wxString& aFpUnicodeName ) const;
std::tuple<wxString, const CFB::COMPOUND_FILE_ENTRY*> FindLibFootprintDirName( const wxString& aFpUnicodeName );
const CFB::COMPOUND_FILE_ENTRY* FindStream( const std::vector<std::string>& aStreamPath ) const;
@ -82,8 +82,14 @@ public:
std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*> GetLibSymbols( const CFB::COMPOUND_FILE_ENTRY* aStart ) const;
private:
void cacheLibFootprintNames();
std::unique_ptr<CFB::CompoundFileReader> m_reader;
std::vector<char> m_buffer;
std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*> m_libFootprintNameCache;
std::map<wxString, wxString> m_libFootprintDirNameCache;
};

View File

@ -603,7 +603,7 @@ void ALTIUM_PCB::Parse( const ALTIUM_COMPOUND_FILE& altiumPcbFi
}
FOOTPRINT* ALTIUM_PCB::ParseFootprint( const ALTIUM_COMPOUND_FILE& altiumLibFile,
FOOTPRINT* ALTIUM_PCB::ParseFootprint( ALTIUM_COMPOUND_FILE& altiumLibFile,
const wxString& aFootprintName )
{
std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( m_board );

View File

@ -112,7 +112,7 @@ public:
void Parse( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
const std::map<ALTIUM_PCB_DIR, std::string>& aFileMapping );
FOOTPRINT* ParseFootprint( const ALTIUM_COMPOUND_FILE& altiumLibFile,
FOOTPRINT* ParseFootprint( ALTIUM_COMPOUND_FILE& altiumLibFile,
const wxString& aFootprintName );
private: