В принципе, эта заметка может рассматриваться и как дополнение к предыдущей сегодняшней теме, и как иллюстрация для распространенного в интернетах мнения о том, что C++ный код излишне многословен.
В левом столбце код, написанный в варианте quick-and-dirty, т.е. быстренько что-нибудь слабать, чтобы заработало как можно скорее. В правом столбце -- немножко доработанный напильником. И там, и там несколько приватных методов класса. Менялись только методы, остальная начинка класса (т.е. атрибуты и публичные методы) не изменилась ни на грамм.
void
evt_data_source( const msg_register_data_source & evt )
{
m_data_sources.push_back( evt.m_data );
if( m_data_sources_count == m_data_sources.size() )
{
this >>= st_light_data_iterations;
m_started_at = std::chrono::high_resolution_clock::now();
start_light_data_iteration();
}
}
void
evt_light_data_iteration_finished()
{
if( m_data_processor_count <= ++m_processor_iterations_passed )
{
if( m_iteration_count <= ++m_iterations_passed )
{
show_result( "light_data",
std::chrono::high_resolution_clock::now() );
this >>= st_heavy_data_iterations;
m_started_at = std::chrono::high_resolution_clock::now();
m_iterations_passed = 0;
start_heavy_data_iteration();
}
else
start_light_data_iteration();
}
}
void
evt_heavy_data_iteration_finished()
{
if( m_data_processor_count <= ++m_processor_iterations_passed )
{
if( m_iteration_count <= ++m_iterations_passed )
{
show_result( "heavy_data",
std::chrono::high_resolution_clock::now() );
so_deregister_agent_coop_normally();
}
else
start_heavy_data_iteration();
}
}
|
|
void
evt_data_source( const msg_register_data_source & evt )
{
m_data_sources.push_back( evt.m_data );
if( m_data_sources_count == m_data_sources.size() )
start_measure< light_data >( st_light_data_iterations );
}
void
evt_light_data_iteration_finished()
{
handle_iteration_finish< light_data >( [this] {
show_result( "light_data" );
start_measure< heavy_data >( st_heavy_data_iterations );
} );
}
void
evt_heavy_data_iteration_finished()
{
handle_iteration_finish< heavy_data >( [this] {
show_result( "heavy_data" );
so_deregister_agent_coop_normally();
} );
}
|
|
Ну а вот вспомогательные методы, которые использовались в трех показанных выше. Никакой магии. Хотя, возможно, многие C++ники до сих пор не знают, что внутри обычного класса можно определять шаблонные методы, причем еще со времен C++98/03. Тем не менее, C++11/14 -- это уже совсем другой C++, не перестаю это повторять, т.к. сам зачастую получаю удовольствие о того, насколько удобнее и проще программировать на C++ сейчас, чем даже лет 6-7 назад.
void
start_light_data_iteration()
{
start_iteration< light_data >();
}
void
start_heavy_data_iteration()
{
start_iteration< heavy_data >();
}
template< typename MSG >
void
start_iteration()
{
m_processor_iterations_passed = 0;
for( auto d : m_data_sources )
so_5::send< MSG >( m_data_mbox,
d->m_name, d->m_suffix, d->m_gauge );
}
void
show_result(
const char * what,
std::chrono::high_resolution_clock::time_point finish_at )
{
using namespace std::chrono;
std::cout << what << ": "
<< duration_cast< microseconds >( finish_at - m_started_at )
.count() / 1000.0 << "ms"
<< std::endl;
}
|
|
template< class MSG >
void
start_measure( const so_5::rt::state_t & state )
{
this >>= state;
m_iterations_passed = 0;
m_started_at = std::chrono::high_resolution_clock::now();
next_iteration< MSG >();
}
template< typename MSG >
void
next_iteration()
{
m_processor_iterations_passed = 0;
for( auto d : m_data_sources )
so_5::send< MSG >( m_data_mbox,
d->m_name, d->m_suffix, d->m_gauge );
}
template< typename MSG, typename ON_MEASURE_FINISH >
void
handle_iteration_finish( ON_MEASURE_FINISH reaction )
{
if( m_data_processor_count <= ++m_processor_iterations_passed )
{
if( m_iteration_count <= ++m_iterations_passed )
reaction();
else
next_iteration< MSG >();
}
}
void
show_result( const char * what )
{
using namespace std::chrono;
std::cout << what << ": "
<< duration_cast< microseconds >( high_resolution_clock::now() -
m_started_at ).count() / 1000.0 << "ms"
<< std::endl;
}
|
|
Что забавно: если сравнивать оба варианта кода целиком, то новый компактнее старого всего на четырнадцать строк. Эту разницу можно было бы почти полностью нивелировать, если бы в старом варианте отказаться от start_light_data_iteration/start_heavy_data_iteration, а вызывать напрямую start_iteration с соответствующим параметром шаблона. При этом еще и вспомогательные методы в новом варианте оказались объемнее. Тем не менее понятность трех основных методов, реализующих основную прикладную логику, изменилась значительно.
Комментариев нет:
Отправить комментарий