|
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) $