KiCad PCB EDA Suite
Loading...
Searching...
No Matches
design_block_info_impl.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
22
23#include <design_block.h>
24#include <design_block_info.h>
26#include <kiway.h>
27#include <locale_io.h>
28#include <lib_id.h>
29#include <progress_reporter.h>
30#include <string_utils.h>
31#include <core/thread_pool.h>
33
34#include <kiplatform/io.h>
35
36#include <wx/textfile.h>
37#include <wx/txtstrm.h>
38#include <wx/wfstream.h>
39
40
42{
44
45 wxASSERT( dbtable );
46
47 const DESIGN_BLOCK* design_block = dbtable->GetEnumeratedDesignBlock( m_nickname, m_dbname );
48
49 if( design_block )
50 {
51 m_keywords = design_block->GetKeywords();
52 m_doc = design_block->GetLibDescription();
53 }
54
55 m_loaded = true;
56}
57
58
59bool DESIGN_BLOCK_LIST_IMPL::CatchErrors( const std::function<void()>& aFunc )
60{
61 try
62 {
63 aFunc();
64 }
65 catch( const IO_ERROR& ioe )
66 {
67 m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) );
68 return false;
69 }
70 catch( const std::exception& se )
71 {
72 // This is a round about way to do this, but who knows what THROW_IO_ERROR()
73 // may be tricked out to do someday, keep it in the game.
74 try
75 {
76 THROW_IO_ERROR( se.what() );
77 }
78 catch( const IO_ERROR& ioe )
79 {
80 m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) );
81 }
82
83 return false;
84 }
85
86 return true;
87}
88
89
91 const wxString* aNickname,
92 PROGRESS_REPORTER* aProgressReporter )
93{
94 long long int generatedTimestamp = 0;
95
96 if( !CatchErrors(
97 [&]()
98 {
99 generatedTimestamp = aTable->GenerateTimestamp( aNickname );
100 } ) )
101 {
102 return false;
103 }
104
105 if( generatedTimestamp == m_list_timestamp )
106 return true;
107
108 // Disable KIID generation: not needed for library parts; sometimes very slow
109 KIID_NIL_SET_RESET reset_kiid;
110
111 m_progress_reporter = aProgressReporter;
112
114 {
116 m_progress_reporter->Report( _( "Fetching design_block libraries..." ) );
117 }
118
119 m_cancelled = false;
120 m_lib_table = aTable;
121
122 // Clear data before reading files
123 m_errors.clear();
124 m_list.clear();
127
128 if( aNickname )
129 {
130 m_queue_in.push( *aNickname );
131 }
132 else
133 {
134 for( const wxString& nickname : aTable->GetLogicalLibs() )
135 m_queue_in.push( nickname );
136 }
137
138
139 loadLibs();
140
141 if( !m_cancelled )
142 {
144 {
147 m_progress_reporter->Report( _( "Loading design_blocks..." ) );
148 }
149
151
154 }
155
156 if( m_cancelled )
157 m_list_timestamp = 0; // God knows what we got before we were canceled
158 else
159 m_list_timestamp = generatedTimestamp;
160
161 return m_errors.empty();
162}
163
164
166{
168 size_t num_returns = m_queue_in.size();
169 std::vector<std::future<size_t>> returns( num_returns );
170
171 auto loader_job =
172 [this]() -> size_t
173 {
174 wxString nickname;
175 size_t retval = 0;
176
177 if( !m_cancelled && m_queue_in.pop( nickname ) )
178 {
179 if( CatchErrors( [this, &nickname]()
180 {
181 m_lib_table->PrefetchLib( nickname );
182 m_queue_out.push( nickname );
183 } ) && m_progress_reporter )
184 {
186 }
187
188 ++retval;
189 }
190
191 return retval;
192 };
193
194 for( size_t ii = 0; ii < num_returns; ++ii )
195 returns[ii] = tp.submit( loader_job );
196
197 for( const std::future<size_t>& ret : returns )
198 {
199 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
200
201 while( status != std::future_status::ready )
202 {
204 m_cancelled = true;
205
206 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
207 }
208 }
209}
210
211
213{
214 LOCALE_IO toggle_locale;
215
216 // Parse the design_blocks in parallel. WARNING! This requires changing the locale, which is
217 // GLOBAL. It is only thread safe to construct the LOCALE_IO before the threads are created,
218 // destroy it after they finish, and block the main (GUI) thread while they work. Any deviation
219 // from this will cause nasal demons.
220 //
221 // TODO: blast LOCALE_IO into the sun
222
225 size_t num_elements = m_queue_out.size();
226 std::vector<std::future<size_t>> returns( num_elements );
227
228 auto db_thread =
229 [ this, &queue_parsed ]() -> size_t
230 {
231 wxString nickname;
232
233 if( m_cancelled || !m_queue_out.pop( nickname ) )
234 return 0;
235
236 wxArrayString dbnames;
237
239 [&]()
240 {
241 m_lib_table->DesignBlockEnumerate( dbnames, nickname, false );
242 } );
243
244 for( wxString dbname : dbnames )
245 {
247 [&]()
248 {
249 auto* dbinfo = new DESIGN_BLOCK_INFO_IMPL( this, nickname, dbname );
250 queue_parsed.move_push( std::unique_ptr<DESIGN_BLOCK_INFO>( dbinfo ) );
251 } );
252
253 if( m_cancelled )
254 return 0;
255 }
256
259
260 return 1;
261 };
262
263 for( size_t ii = 0; ii < num_elements; ++ii )
264 returns[ii] = tp.submit( db_thread );
265
266 for( const std::future<size_t>& ret : returns )
267 {
268 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
269
270 while( status != std::future_status::ready )
271 {
274
275 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
276 }
277 }
278
279 std::unique_ptr<DESIGN_BLOCK_INFO> dbi;
280
281 while( queue_parsed.pop( dbi ) )
282 m_list.push_back( std::move( dbi ) );
283
284 std::sort( m_list.begin(), m_list.end(),
285 []( std::unique_ptr<DESIGN_BLOCK_INFO> const& lhs,
286 std::unique_ptr<DESIGN_BLOCK_INFO> const& rhs ) -> bool
287 {
288 return *lhs < *rhs;
289 } );
290}
291
292
294 m_list_timestamp( 0 ), m_progress_reporter( nullptr ), m_cancelled( false )
295{
296}
virtual void load() override
lazily load stuff not filled in by constructor. This may throw IO_ERRORS.
DESIGN_BLOCK_LIST * m_owner
provides access to DESIGN_BLOCK_LIB_TABLE
wxString m_nickname
library as known in DESIGN_BLOCK_LIB_TABLE
wxString m_dbname
Module name.
wxString m_keywords
Design block keywords.
wxString m_doc
Design block description.
void PrefetchLib(const wxString &aNickname)
If possible, prefetches the specified library (e.g.
long long GenerateTimestamp(const wxString *aNickname)
Generate a hashed timestamp representing the last-mod-times of the library indicated by aNickname,...
const DESIGN_BLOCK * GetEnumeratedDesignBlock(const wxString &aNickname, const wxString &aDesignBlockName)
A version of DesignBlockLoad() for use after DesignBlockEnumerate() for more efficient cache manageme...
void DesignBlockEnumerate(wxArrayString &aDesignBlockNames, const wxString &aNickname, bool aBestEfforts)
Return a list of design block names contained within the library given by aNickname.
SYNC_QUEUE< wxString > m_queue_in
bool CatchErrors(const std::function< void()> &aFunc)
Call aFunc, pushing any IO_ERRORs and std::exceptions it throws onto m_errors.
SYNC_QUEUE< wxString > m_queue_out
PROGRESS_REPORTER * m_progress_reporter
bool ReadDesignBlockFiles(DESIGN_BLOCK_LIB_TABLE *aTable, const wxString *aNickname=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr) override
Read all the design blocks provided by the combination of aTable and aNickname.
DESIGN_BLOCK_LIB_TABLE * GetTable() const
DESIGN_BLOCK_LIB_TABLE * m_lib_table
no ownership
ERRLIST m_errors
some can be PARSE_ERRORs also
const wxString & GetKeywords() const
Definition: design_block.h:38
const wxString & GetLibDescription() const
Definition: design_block.h:35
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
RAII class to safely set/reset nil KIIDs for use in footprint/symbol loading.
Definition: kiid.h:230
std::vector< wxString > GetLogicalLibs()
Return the logical library names, all of them that are pertinent to a look up done on this LIB_TABLE.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:49
A progress reporter interface for use in multi-threaded environments.
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
virtual void AdvanceProgress()=0
Increment the progress bar length (inside the current virtual zone).
virtual void SetMaxProgress(int aMaxProgress)=0
Fix the value that gives the 100 percent progress bar length (inside the current virtual zone).
Synchronized, locking queue.
Definition: sync_queue.h:32
bool pop(T &aReceiver)
Pop a value if the queue into the provided variable.
Definition: sync_queue.h:63
bool empty() const
Return true if the queue is empty.
Definition: sync_queue.h:82
void clear()
Clear the queue.
Definition: sync_queue.h:100
size_t size() const
Return the size of the queue.
Definition: sync_queue.h:91
void push(T const &aValue)
Push a value onto the queue.
Definition: sync_queue.h:41
void move_push(T &&aValue)
Move a value onto the queue.
Definition: sync_queue.h:50
#define _(s)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
static thread_pool * tp
Definition: thread_pool.cpp:30
BS::thread_pool thread_pool
Definition: thread_pool.h:30
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
Definition: thread_pool.cpp:32
Definition of file extensions used in Kicad.