Здравствуйте, night beast, Вы писали:
C>>Думаю насчёт тонкой обёртки в виде реализации istream/ostream. Оверхеда не избежать, но большая часть моего собственного кода легко переделывается на мои потоки. Я туда уже и форматированный вывод даже добавил, только сделаный не криво (как в стандартной библиотеке). NB>посмотри еще google::protobuf::io. NB>хотя свой велосипед наверно тоже нормальное решение.
О! Спасибо. Я как раз собирался использовать protobuf.
У них интересное решение с ZeroCopy, надо посмотреть.
Здравствуйте, Cyberax, Вы писали: C>Здравствуйте, gegMOPO4, Вы писали: C>>>А stringbuf — виртуальный. Так что никуда не деться, виртуальные вызовы будут в любом случае. MOP>>Но не для каждой операции В/В. C>Для КАЖДОЙ операции. C>Вызов read() у istream выливается в: C>
C>Упс. C>Т.е. в STL не просто одно, а целых ДВА непрямых вызова — как минимум. Сначала непрямой вызов rdbuf(), потом виртуальный вызов xsgetn(). Это ещё не считая проверки всяких failbit и прочей гадости. C>И это на КАЖДЫЙ ввод/вывод.
Да, тут я напутал, был неправ.
Однако, побайтный В/В (put, get и т.п.) работают непосредственно с буфером и виртуальных вызовов избегают (как и их родственники из сишной билиотеки, реализованные даже макросами).
Здравствуйте, Cyberax, Вы писали: C>Здравствуйте, gegMOPO4, Вы писали: C>>>basic_stringbuf вылезает примерно в 100 строк!! Не считая ещё прилагающихся к нему basic_stringstream. Не буду я такой ублюдочный интерфейс даже трогать. MOP>>Это же библиотечная реализация, там большая часть — комментарии, тайпдефы и прочие пляски, ненужные конкретному типу. basic_stringstream же тривиален, содержит только конструктор и прокси-методы. C>Ну приведи простейшую реализацию.
Простейшая реализация буфера для ввода:
class raw_input_streambuf : public basic_streambuf<char>
{
public:
raw_input_streambuf(const char_type* s, streamsize n)
{
setg(s, s, s + n);
}
};
И для вывода:
class raw_output_streambuf : public basic_streambuf<char>
{
public:
raw_output_streambuf(const char_type* s, streamsize n)
{
setp(s, s + n);
}
};
Можно объединить для ввода/вывода (хотя это редко нужно). Поскольку реализация простейшая, позиционирование не работает (оно тоже не всегда нужно). Если нужно, то реализация для ввода:
...
protected:
virtual pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode mode = ios_base::in)
{
if (ios_base::in & mode)
{
const char_type* beg = eback();
if (way == ios_base::cur)
off += gptr() - beg;
else if (way == ios_base::end)
off += egptr() - beg;
if (0 <= off && off <= egptr() - beg)
{
gbump(beg + off - gptr());
return pos_type(off);
}
}
return pos_type(off_type(-1));
}
virtual pos_type seekpos(pos_type sp, ios_base::openmode mode = ios_base::in)
{
if (ios_base::in & mode)
{
const char_type* beg = eback();
const off_type pos(sp);
if (0 <= pos && pos <= egptr() - beg)
{
gbump(beg + pos - gptr());
return sp;
}
}
return pos_type(off_type(-1));
}
...
Аналогично для вывода (только другие методы вызываются).
Здравствуйте, gegMOPO4, Вы писали:
MOP>Однако, побайтный В/В (put, get и т.п.) работают непосредственно с буфером и виртуальных вызовов избегают (как и их родственники из сишной билиотеки, реализованные даже макросами).
Каким образом? Там всё выливается в xsgetn в итоге, который виртуален.
Собственно, если нужно виртуальное поведение, то без аналога виртуального вызова не обойтись.
Здравствуйте, Cyberax, Вы писали: C>Здравствуйте, gegMOPO4, Вы писали: MOP>>Однако, побайтный В/В (put, get и т.п.) работают непосредственно с буфером и виртуальных вызовов избегают (как и их родственники из сишной билиотеки, реализованные даже макросами). C>Каким образом? Там всё выливается в xsgetn в итоге, который виртуален.
xsgetn как раз вообще не используется (он и нужен-то только для возможности оптимизации массового В/В, но для реализации не необходим, достаточно поведения по умолчанию). По возможности используется буфер в памяти, и лишь когда его нет или закончился — вызывается underflow/overflow. В приведённой мной реализации вся работа идёт с буфером, до виртуального вызова не доходит.