eao197 on the Web Сайт Евгения Охотникова |
[ Главная | Проекты | Описания | Об авторе | Лицензия ] |
C++ tricks: local_class
При реализации в ObjESSty способа хранения
размерности контейнеров в стиле ASN1 BER возникла задача:
- если значение размерности меньше или равно 127, то значение храниться в одном
байте;
- если значение больше 127, то первый байт хранит количество байт с двоичным
образом размерности. При этом старший, седьмой, бит первого байта установлен
в единицу, а биты с шестого по нулевой содержат количество байт, расположенных
следом.
Первоначальный набросок реализации выглядел так:
const oess_1::uint_t max_quantity_image_size = 5; ... void obinstream_t::write( const oess_1::defs::quantity_t & p ) { oess_1::uchar_t image[ max_quantity_image_size ]; oess_1::uint_t length = 1; oess_1::uint_t v = p.value(); if( v <= 127u ) // Достаточно всего одного байта для сохранения длины. image[ max_quantity_image_size - length ] = static_cast< oess_1::uchar_t >( v ); else { // Потребуется еще и первый байт, в котором будет выставлен // старший бит и будет содержаться количество байт с // представлением quantity. for(; v; ++length, v >>= 8 ) { image[ max_quantity_image_size - length ] = static_cast< oess_1::uchar_t >( v & 0xffu ); } // Особенность данного алгоритма в том, что на момент выхода // из цикла length на единицу больше количества байт, // в которых сохранено значение quantity. Т.е. length // содержит количество байт, которые должно быть записано в // выходной поток. image[ max_quantity_image_size - length ] = static_cast< oess_1::uchar_t >( ( image.length() - 1 ) | 0x80u ); } write( &image[ max_quantity_image_size - length ], length ); }
Но меня смущало слишком много вычислений индексов при обращении к image и слишком много static_cast-ов. Среди этих продробностей терялась логика самого алгоритма. Для того, чтобы отделить логику от лишних деталей был сделан вспомогательный класс, который отвечает за хранение image и length. А для того, чтобы класс не засорял глобальное пространство имен, он был сделан локальным классом в методе write().
В результате код write() получился более объемным, но зато гораздо более понятным для меня:
void obinstream_t::write( const oess_1::defs::quantity_t & p ) { /*! * Вспомогательный класс для инкапсуляции манипуляций с содержимым * вектора двоичного образа. */ class image_manipulator_t { oess_1::uchar_t m_image[ max_quantity_image_size ]; oess_1::uint_t m_length; public : image_manipulator_t() : m_length( 1 ) {} void store( oess_1::uint_t v ) { m_image[ max_quantity_image_size - m_length ] = static_cast< oess_1::uchar_t >( v ); } void next() { ++m_length; } const oess_1::uint_t length() const { return m_length; } const oess_1::uchar_t * ptr() const { return &m_image[ max_quantity_image_size - m_length ]; } }; image_manipulator_t image; oess_1::uint_t v = p.value(); if( v <= 127u ) // Достаточно всего одного байта для сохранения длины. image.store( v ); else { // Потребуется еще и первый байт, в котором будет выставлен // старший бит и будет содержаться количество байт с // представлением quantity. for(; v; image.next(), v >>= 8 ) { image.store( v & 0xffu ); } // Особенность данного алгоритма в том, что на момент выхода // из цикла image.length() на единицу больше количества байт, // в которых сохранено значение quantity. Т.е. image.length() // содержит количество байт, которые должно быть записано в // выходной поток. image.store( ( image.length() - 1 ) | 0x80u ); } write( image.ptr(), image.length() ); }
© 2003-2005 Е.А. Охотников
$LastChangedDate: 2006-06-16 14:40:57 +0400 (РџС‚, 16 РёСЋРЅ 2006) $