IO library
От: Cyberax Марс  
Дата: 14.11.11 02:06
Оценка:
Ищё IO-библиотеку, построенную на виртуальных классах потоков.

Т.е. классический input_stream, от которого наследуется file_input_stream, с возможностью их передать в input_stream_formatter для форматированного вывода и т.п. В общем, чтоб было как в Java

Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код.
Sapienti sat!
Re: IO library
От: gegMOPO4  
Дата: 14.11.11 12:52
Оценка:
Здравствуйте, Cyberax, Вы писали:
C>Ищё IO-библиотеку, построенную на виртуальных классах потоков.
C>Т.е. классический input_stream, от которого наследуется file_input_stream, с возможностью их передать в input_stream_formatter для форматированного вывода и т.п. В общем, чтоб было как в Java
C>Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код.

Чем не нравятся стандартные потоки C++? Виртуальность в них вынесена на уровень ниже, в streambuf.
Re[2]: IO library
От: Cyberax Марс  
Дата: 14.11.11 15:36
Оценка: +1
Здравствуйте, gegMOPO4, Вы писали:

C>>Ищё IO-библиотеку, построенную на виртуальных классах потоков.

C>>Т.е. классический input_stream, от которого наследуется file_input_stream, с возможностью их передать в input_stream_formatter для форматированного вывода и т.п. В общем, чтоб было как в Java
C>>Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код.
MOP>Чем не нравятся стандартные потоки C++? Виртуальность в них вынесена на уровень ниже, в streambuf.
Потому, что там дизайн кретенический.
1) Ну нафиг мне в низкоуровневом потоке работать с локалью?? Туда уже должны чистые потоки байт приходить.
2) Мне нужен дизайн потока, а не буффера.
Sapienti sat!
Re[3]: IO library
От: gegMOPO4  
Дата: 14.11.11 16:09
Оценка:
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, gegMOPO4, Вы писали:
C>>>Ищё IO-библиотеку, построенную на виртуальных классах потоков.
C>>>Т.е. классический input_stream, от которого наследуется file_input_stream, с возможностью их передать в input_stream_formatter для форматированного вывода и т.п. В общем, чтоб было как в Java
C>>>Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код.
MOP>>Чем не нравятся стандартные потоки C++? Виртуальность в них вынесена на уровень ниже, в streambuf.
C>Потому, что там дизайн кретенический.
C>1) Ну нафиг мне в низкоуровневом потоке работать с локалью?? Туда уже должны чистые потоки байт приходить.

Выше речь шла о форматированном выводе. Зачем же потоки вам нужны? Как собираетесь их использовать?

C>2) Мне нужен дизайн потока, а не буффера.


Что вы под этим подразумеваете? Потокам Jаva соответствуют буферы C++, а потоки С++ — это скорее форматтеры (или принтеры) Java.
Re[4]: IO library
От: Cyberax Марс  
Дата: 14.11.11 16:20
Оценка:
Здравствуйте, gegMOPO4, Вы писали:

C>>1) Ну нафиг мне в низкоуровневом потоке работать с локалью?? Туда уже должны чистые потоки байт приходить.

MOP>Выше речь шла о форматированном выводе. Зачем же потоки вам нужны? Как собираетесь их использовать?
Мне нужно работать с потоками байтов. Опционально с форматированым выводом, с помощью форматтеров, работающих поверх нетипизированного потока.

C>>2) Мне нужен дизайн потока, а не буффера.

MOP>Что вы под этим подразумеваете? Потокам Jаva соответствуют буферы C++, а потоки С++ — это скорее форматтеры (или принтеры) Java.
Не соответствуют. Потоки в Java состоят буквально из одного метода "write(void *data, size_t ln)", остальная функциональность добавляется в наследниках или опциональна.

streambuf — это абстракция буфера, в нём есть underflow/overflow, seek и прочее. Причём уже в streambuf есть поддержка локалей. Самый близкий мне аналог — это вроде бы istream, но там всё так криво, что на него смотреть даже не хочется.
Sapienti sat!
Re[5]: IO library
От: gegMOPO4  
Дата: 14.11.11 16:47
Оценка:
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, gegMOPO4, Вы писали:
C>>>1) Ну нафиг мне в низкоуровневом потоке работать с локалью?? Туда уже должны чистые потоки байт приходить.
MOP>>Выше речь шла о форматированном выводе. Зачем же потоки вам нужны? Как собираетесь их использовать?
C>Мне нужно работать с потоками байтов. Опционально с форматированым выводом, с помощью форматтеров, работающих поверх нетипизированного потока.

read/write, get/put. Локаль тут никаким боком.

C>>>2) Мне нужен дизайн потока, а не буффера.

MOP>>Что вы под этим подразумеваете? Потокам Jаva соответствуют буферы C++, а потоки С++ — это скорее форматтеры (или принтеры) Java.
C>Не соответствуют. Потоки в Java состоят буквально из одного метода "write(void *data, size_t ln)", остальная функциональность добавляется в наследниках или опциональна.

OutputStream — 5 виртуальных методов, InputStream — 9. Не считая конструкторов. Буферы С++ проще и эффективнее.

C>streambuf — это абстракция буфера, в нём есть underflow/overflow, seek и прочее. Причём уже в streambuf есть поддержка локалей. Самый близкий мне аналог — это вроде бы istream, но там всё так криво, что на него смотреть даже не хочется.


Пока не используете «широкие» потоки, локаль пусть вас не волнует.
Re[6]: IO library
От: Cyberax Марс  
Дата: 14.11.11 17:15
Оценка:
Здравствуйте, gegMOPO4, Вы писали:

C>>Мне нужно работать с потоками байтов. Опционально с форматированым выводом, с помощью форматтеров, работающих поверх нетипизированного потока.

MOP>read/write, get/put. Локаль тут никаким боком.
Про "virtual void imbue(const locale&)" забываем?

Ну давай смотреть. Смотрим класс strstreambuf, в нём реализованы:
    virtual int_type overflow(int_type __c  = _Traits::eof());
    virtual int_type pbackfail(int_type __c = _Traits::eof());
    virtual int_type underflow();
    virtual _Base* setbuf(char* __buf, streamsize __n);
    virtual pos_type seekoff(off_type __off, ios_base::seekdir __dir,
                 ios_base::openmode __mode
                 = ios_base::in | ios_base::out);
    virtual pos_type seekpos(pos_type __pos, ios_base::openmode __mode
                 = ios_base::in | ios_base::out);


На минимальный интерфейс ну никак не тянет.

C>>Не соответствуют. Потоки в Java состоят буквально из одного метода "write(void *data, size_t ln)", остальная функциональность добавляется в наследниках или опциональна.

MOP>OutputStream — 5 виртуальных методов, InputStream — 9. Не считая конструкторов. Буферы С++ проще и эффективнее.
Для реализации InputStream достаточно переопределить один метод "public abstract int read() throws IOException;", остальные методы имеют реализацию по умолчанию.

(если бы я дизайнил потоки Java, то сделал бы их немног по-другому, но базовая идея там вполне разумная)

C>>streambuf — это абстракция буфера, в нём есть underflow/overflow, seek и прочее. Причём уже в streambuf есть поддержка локалей. Самый близкий мне аналог — это вроде бы istream, но там всё так криво, что на него смотреть даже не хочется.

MOP>Пока не используете «широкие» потоки, локаль пусть вас не волнует.
Тем не менее, она есть, что мне УЖЕ не жутко не нравится. Некрасиво.
Sapienti sat!
Re[7]: IO library
От: gegMOPO4  
Дата: 14.11.11 18:44
Оценка: +1
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, gegMOPO4, Вы писали:
C>>>Мне нужно работать с потоками байтов. Опционально с форматированым выводом, с помощью форматтеров, работающих поверх нетипизированного потока.
MOP>>read/write, get/put. Локаль тут никаким боком.
C>Про "virtual void imbue(const locale&)" забываем?

А зачем вам imbue при работе с потоком байт?

C>Ну давай смотреть. Смотрим класс strstreambuf, в нём реализованы:

C>
C>    virtual int_type overflow(int_type __c  = _Traits::eof());
C>    virtual int_type pbackfail(int_type __c = _Traits::eof());
C>    virtual int_type underflow();
C>    virtual _Base* setbuf(char* __buf, streamsize __n);
C>    virtual pos_type seekoff(off_type __off, ios_base::seekdir __dir,
C>                 ios_base::openmode __mode
C>                 = ios_base::in | ios_base::out);
C>    virtual pos_type seekpos(pos_type __pos, ios_base::openmode __mode
C>                 = ios_base::in | ios_base::out);
C>

C>На минимальный интерфейс ну никак не тянет.

Это из-за того, что буфер используется и для ввода, и для вывода. Да и какое дело вам до интерфейса буфера? Его пользователь — поток, а вам он предоставляет более удобный и быстрый интерфейс read/write, get/put.

C>>>Не соответствуют. Потоки в Java состоят буквально из одного метода "write(void *data, size_t ln)", остальная функциональность добавляется в наследниках или опциональна.

MOP>>OutputStream — 5 виртуальных методов, InputStream — 9. Не считая конструкторов. Буферы С++ проще и эффективнее.
C>Для реализации InputStream достаточно переопределить один метод "public abstract int read() throws IOException;", остальные методы имеют реализацию по умолчанию.

И дёргать виртуальный метод для каждого байта. Нет, то, что допустимо в Java, в C++ совершенно неприемлемо, тем более в стандартной библиотеке. Здесь умеют считать байты и такты, и JIT не сгладит лишний оверхед. streambuf имеет виртуальные методы, но дёргаются они как можно реже. Это интерфейс, ориентированный на производительность.
Re[8]: IO library
От: Cyberax Марс  
Дата: 14.11.11 19:12
Оценка:
Здравствуйте, gegMOPO4, Вы писали:

C>>Про "virtual void imbue(const locale&)" забываем?

MOP>А зачем вам imbue при работе с потоком байт?
Так ведь нужно реализовать.

C>>На минимальный интерфейс ну никак не тянет.

MOP>Это из-за того, что буфер используется и для ввода, и для вывода. Да и какое дело вам до интерфейса буфера? Его пользователь — поток, а вам он предоставляет более удобный и быстрый интерфейс read/write, get/put.
Я не знаю, у меня мозга не хватает, чтобы понять всю структуру IO-потоков в С++. Где можно взять пример как их использовать, чтобы сделать виртуальный поток для неформатированного вывода, который можно создавать/уничтожать с минимальным оверхедом и передавать по виртуальной базе?

Если что, мне надо потоки, которые можно создать полностью на стеке на основе 5-8 байтных статических буфферов.

C>>Для реализации InputStream достаточно переопределить один метод "public abstract int read() throws IOException;", остальные методы имеют реализацию по умолчанию.

MOP>И дёргать виртуальный метод для каждого байта.
Это МИНИМАЛЬНЫЙ интерфейс. Если меня он удовлетворяет (к примеру, если у меня устройство один фиг медленное или я пишу всего пару байт), то мне больше ничего не надо. Я так же могу переопределить метод, который пишет массив байт — и будет всё ОК. Я бы сделал фундаментальным именно метод, который пишет массив байт, но это мелочи жизни уже.
Sapienti sat!
Re[9]: IO library
От: gegMOPO4  
Дата: 14.11.11 20:17
Оценка:
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, gegMOPO4, Вы писали:
C>>>Про "virtual void imbue(const locale&)" забываем?
MOP>>А зачем вам imbue при работе с потоком байт?
C>Так ведь нужно реализовать.

Не нужно реализовывать.

C>>>На минимальный интерфейс ну никак не тянет.

MOP>>Это из-за того, что буфер используется и для ввода, и для вывода. Да и какое дело вам до интерфейса буфера? Его пользователь — поток, а вам он предоставляет более удобный и быстрый интерфейс read/write, get/put.
C>Я не знаю, у меня мозга не хватает, чтобы понять всю структуру IO-потоков в С++. Где можно взять пример как их использовать, чтобы сделать виртуальный поток для неформатированного вывода, который можно создавать/уничтожать с минимальным оверхедом и передавать по виртуальной базе?

База у потоков не виртуальная. Передаются потоки по ссылке. А вот вся специфичность определяется виртуальным буффером, который задаётся при инициализации потока. В результате всё множество методов и операторов потока невиртуально и инлайнится, а виртуальные методы вызываются только когда нужно сбросить/подтянуть очередную порцию данных в буффер, раз на много операций.

У Страуструпа расписано немного подробнее, чем в Стандарте. Этого достаточно. Можете также посмотреть реализацию строковых и файловых буферов (или сторонние реализации для gzip и т.п.).

C>Если что, мне надо потоки, которые можно создать полностью на стеке на основе 5-8 байтных статических буфферов.


Если вам критично по скорости/памяти создание именно на стеке и строковые потоки не подходят, то вам скорее всего нужны не потоки, а итераторы (или генераторы).

Впрочем, можно создать и буфер статичного размера. Реализация будет намного проще строкового, большинство операций останутся пустыми, всю работу можно проделать в конструкторе.

C>>>Для реализации InputStream достаточно переопределить один метод "public abstract int read() throws IOException;", остальные методы имеют реализацию по умолчанию.

MOP>>И дёргать виртуальный метод для каждого байта.
C>Это МИНИМАЛЬНЫЙ интерфейс. Если меня он удовлетворяет (к примеру, если у меня устройство один фиг медленное или я пишу всего пару байт), то мне больше ничего не надо. Я так же могу переопределить метод, который пишет массив байт — и будет всё ОК. Я бы сделал фундаментальным именно метод, который пишет массив байт, но это мелочи жизни уже.

Принцип C++ — zero overhead. Вы не платите за возможности, которые не используете. А если платите — то минимальную цену. Дёргать виртуальный метод на каждую операцию — слишком высокая цена для C++ (ведь можно дешевле). Поэтому пользователь пользуется богатым невиртуальным интерфейсом потоков (который не нужно переопределять), а уже поток внутри использует буферизацию, дёргая виртуальные методы только тогда, когда без этого не обойтись. И интерфейс этих виртуальных методов разработан для потребности потоков.

Это ООП наизнанку. Паттерн «стратегия».
Re[10]: IO library
От: Cyberax Марс  
Дата: 14.11.11 20:25
Оценка:
Здравствуйте, gegMOPO4, Вы писали:

C>>Я не знаю, у меня мозга не хватает, чтобы понять всю структуру IO-потоков в С++. Где можно взять пример как их использовать, чтобы сделать виртуальный поток для неформатированного вывода, который можно создавать/уничтожать с минимальным оверхедом и передавать по виртуальной базе?

MOP>База у потоков не виртуальная. Передаются потоки по ссылке. А вот вся специфичность определяется виртуальным буффером, который задаётся при инициализации потока.
Ну вот как его сделать-то?

MOP>У Страуструпа расписано немного подробнее, чем в Стандарте. Этого достаточно. Можете также посмотреть реализацию строковых и файловых буферов (или сторонние реализации для gzip и т.п.).

Ага. Посмотрел. Мозг выпал.

C>>Если что, мне надо потоки, которые можно создать полностью на стеке на основе 5-8 байтных статических буфферов.

MOP>Если вам критично по скорости/памяти создание именно на стеке и строковые потоки не подходят, то вам скорее всего нужны не потоки, а итераторы (или генераторы).
Нельзя. Нету у итераторов общей виртуальной базы, а мне именно виртуальность нужна — чтобы библиотечный код во внешней библиотеке быстро работал с произвольной реализацией потоков.

C>>Это МИНИМАЛЬНЫЙ интерфейс. Если меня он удовлетворяет (к примеру, если у меня устройство один фиг медленное или я пишу всего пару байт), то мне больше ничего не надо. Я так же могу переопределить метод, который пишет массив байт — и будет всё ОК. Я бы сделал фундаментальным именно метод, который пишет массив байт, но это мелочи жизни уже.

MOP>Принцип C++ — zero overhead. Вы не платите за возможности, которые не используете. А если платите — то минимальную цену. Дёргать виртуальный метод на каждую операцию — слишком высокая цена для C++ (ведь можно дешевле).
Дешевле можно, но только если весь клиентский код работает с конкретной реализацией потоков. Иначе в любом случае нужен где-то виртуальный вызов, и он есть, кстати.

MOP>Это ООП наизнанку. Паттерн «стратегия».

Это не ООП наизнанку, это полный идиотизм дизайнеров. Можно было сделать намного проще и удобнее, с тем же оверхедом (один виртуальный вызов на операцию).
Sapienti sat!
Re[11]: IO library
От: gegMOPO4  
Дата: 15.11.11 10:10
Оценка:
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, gegMOPO4, Вы писали:
C>>>Я не знаю, у меня мозга не хватает, чтобы понять всю структуру IO-потоков в С++. Где можно взять пример как их использовать, чтобы сделать виртуальный поток для неформатированного вывода, который можно создавать/уничтожать с минимальным оверхедом и передавать по виртуальной базе?
MOP>>База у потоков не виртуальная. Передаются потоки по ссылке. А вот вся специфичность определяется виртуальным буффером, который задаётся при инициализации потока.
C>Ну вот как его сделать-то?

Создаёте новый класс class mystringbuf : public std::streambuf. Внутрь засовываете члены-данные и переопределяете необходимые виртуальные функции. Потом:
void output(std::ostream &);
...
mystringbuf buf;
std::ostream os(&buf)
output(os);


Можно для удобства завести myistream/myostream, содержащих mystringbuf внутри. Именно так устроены строковые и файловые потоки. Экономия — одна строчка на поток.

MOP>>У Страуструпа расписано немного подробнее, чем в Стандарте. Этого достаточно. Можете также посмотреть реализацию строковых и файловых буферов (или сторонние реализации для gzip и т.п.).

C>Ага. Посмотрел. Мозг выпал.

C>>>Если что, мне надо потоки, которые можно создать полностью на стеке на основе 5-8 байтных статических буфферов.


А можна и готовое использовать.
char data[5];
std::stringbuf buf;
buf.pubsetbuf(data, 5);
std::ostream os(&buf)
output(os);


Оверхед будет из-за внутренней строки. Возьмите stringbuf, выбросьте внутреннюю строку, засуньте data внутрь — и будет то, что надо.

C>>>Это МИНИМАЛЬНЫЙ интерфейс. Если меня он удовлетворяет (к примеру, если у меня устройство один фиг медленное или я пишу всего пару байт), то мне больше ничего не надо. Я так же могу переопределить метод, который пишет массив байт — и будет всё ОК. Я бы сделал фундаментальным именно метод, который пишет массив байт, но это мелочи жизни уже.

MOP>>Принцип C++ — zero overhead. Вы не платите за возможности, которые не используете. А если платите — то минимальную цену. Дёргать виртуальный метод на каждую операцию — слишком высокая цена для C++ (ведь можно дешевле).
C>Дешевле можно, но только если весь клиентский код работает с конкретной реализацией потоков. Иначе в любом случае нужен где-то виртуальный вызов, и он есть, кстати.

Ну так в C++ на все потоки одна реализация (sstream и fstream отличаются только косметически).

MOP>>Это ООП наизнанку. Паттерн «стратегия».

C>Это не ООП наизнанку, это полный идиотизм дизайнеров. Можно было сделать намного проще и удобнее, с тем же оверхедом (один виртуальный вызов на операцию).

Один виртуальный вызов на операцию — уже дорого. В вышеприведённых примерах возможно не будет ни одного виртуального вызова.
Re[12]: IO library
От: Cyberax Марс  
Дата: 15.11.11 16:14
Оценка: :)
Здравствуйте, gegMOPO4, Вы писали:

MOP>Можно для удобства завести myistream/myostream, содержащих mystringbuf внутри. Именно так устроены строковые и файловые потоки. Экономия — одна строчка на поток.

basic_stringbuf вылезает примерно в 100 строк!! Не считая ещё прилагающихся к нему basic_stringstream. Не буду я такой ублюдочный интерфейс даже трогать.

C>>>>Если что, мне надо потоки, которые можно создать полностью на стеке на основе 5-8 байтных статических буфферов.

MOP>А можна и готовое использовать.
MOP>
MOP>char data[5];
MOP>std::stringbuf buf;
MOP>buf.pubsetbuf(data, 5);
MOP>std::ostream os(&buf)
MOP>output(os);
MOP>

MOP>Оверхед будет из-за внутренней строки. Возьмите stringbuf, выбросьте внутреннюю строку, засуньте data внутрь — и будет то, что надо.
Не пойдёт, хотя бы из-за семантики pubsetbuf. Её реализаторы имеют право реализовать её вот так:
      __streambuf_type* 
      pubsetbuf(char_type* __s, streamsize __n) 
      { return this->setbuf(__s, __n); }

      virtual basic_streambuf<char_type,_Traits>* 
      setbuf(char_type*, streamsize)
      {    return this; }

(кто там что про виртуальные вызовы, кстати, говорил?)

C>>Дешевле можно, но только если весь клиентский код работает с конкретной реализацией потоков. Иначе в любом случае нужен где-то виртуальный вызов, и он есть, кстати.

MOP>Ну так в C++ на все потоки одна реализация (sstream и fstream отличаются только косметически).
А stringbuf — виртуальный. Так что никуда не деться, виртуальные вызовы будут в любом случае.

MOP>>>Это ООП наизнанку. Паттерн «стратегия».

C>>Это не ООП наизнанку, это полный идиотизм дизайнеров. Можно было сделать намного проще и удобнее, с тем же оверхедом (один виртуальный вызов на операцию).
MOP>Один виртуальный вызов на операцию — уже дорого. В вышеприведённых примерах возможно не будет ни одного виртуального вызова.
В вышеприведённом примере их как минимум 4 штуки только ДЛЯ ИНИЦИАЛИЗАЦИИ. Далее для каждой операции будет один-два виртуальных вызова + промежуточный слой + проверка локали.
Sapienti sat!
Re: IO library
От: night beast СССР  
Дата: 15.11.11 16:41
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Ищё IO-библиотеку, построенную на виртуальных классах потоков.


C>Т.е. классический input_stream, от которого наследуется file_input_stream, с возможностью их передать в input_stream_formatter для форматированного вывода и т.п. В общем, чтоб было как в Java


C>Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код.


QT::QIODevice не подходит?
Re[2]: IO library
От: Cyberax Марс  
Дата: 15.11.11 16:52
Оценка:
Здравствуйте, night beast, Вы писали:

C>>Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код.

NB>QT::QIODevice не подходит?
Тоже тяжеловесное и кривое.

Пока велосипедирую. Получается что-то вроде:
    class input_stream
    {
    public:
        virtual ~input_stream() {};
        virtual void read(void *data, size_t bytes)=0;
    };

    class buf_input_stream : public input_stream
    {
        typedef std::vector<unsigned char> buf_t;
        buf_t buffer;
        buf_t::const_iterator pos;
    public:
...
        virtual void read(void *data, size_t bytes)
        {
            if (buffer.end()-pos < bytes)
                throw std::out_of_range("Premature end of buffer");

            std::copy(pos, pos+bytes, static_cast<char*>(data));
            pos += bytes;
        }
    };

И манипуляторы к нему. Сейчас думаю как менее криво это пришпилить к стандартным потокам.
Sapienti sat!
Re[3]: IO library
От: night beast СССР  
Дата: 15.11.11 17:05
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Здравствуйте, night beast, Вы писали:


C>>>Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код.

NB>>QT::QIODevice не подходит?
C>Тоже тяжеловесное и кривое.

есть такое дело.

C>Пока велосипедирую. Получается что-то вроде:

C>И манипуляторы к нему. Сейчас думаю как менее криво это пришпилить к стандартным потокам.

преобразовывать к stringstream?
Re[4]: IO library
От: Cyberax Марс  
Дата: 15.11.11 17:10
Оценка:
Здравствуйте, night beast, Вы писали:

C>>Пока велосипедирую. Получается что-то вроде:

C>>И манипуляторы к нему. Сейчас думаю как менее криво это пришпилить к стандартным потокам.
NB>преобразовывать к stringstream?
Думаю насчёт тонкой обёртки в виде реализации istream/ostream. Оверхеда не избежать, но большая часть моего собственного кода легко переделывается на мои потоки. Я туда уже и форматированный вывод даже добавил, только сделаный не криво (как в стандартной библиотеке).
Sapienti sat!
Re[13]: IO library
От: gegMOPO4  
Дата: 15.11.11 17:16
Оценка:
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, gegMOPO4, Вы писали:
MOP>>Можно для удобства завести myistream/myostream, содержащих mystringbuf внутри. Именно так устроены строковые и файловые потоки. Экономия — одна строчка на поток.
C>basic_stringbuf вылезает примерно в 100 строк!! Не считая ещё прилагающихся к нему basic_stringstream. Не буду я такой ублюдочный интерфейс даже трогать.

Это же библиотечная реализация, там большая часть — комментарии, тайпдефы и прочие пляски, ненужные конкретному типу. basic_stringstream же тривиален, содержит только конструктор и прокси-методы.

C>>>>>Если что, мне надо потоки, которые можно создать полностью на стеке на основе 5-8 байтных статических буфферов.

MOP>>А можна и готовое использовать.
MOP>>
MOP>>char data[5];
MOP>>std::stringbuf buf;
MOP>>buf.pubsetbuf(data, 5);
MOP>>std::ostream os(&buf)
MOP>>output(os);
MOP>>

MOP>>Оверхед будет из-за внутренней строки. Возьмите stringbuf, выбросьте внутреннюю строку, засуньте data внутрь — и будет то, что надо.
C>Не пойдёт, хотя бы из-за семантики pubsetbuf. Её реализаторы имеют право реализовать её вот так:
C>
C>      __streambuf_type* 
C>      pubsetbuf(char_type* __s, streamsize __n) 
C>      { return this->setbuf(__s, __n); }

C>      virtual basic_streambuf<char_type,_Traits>* 
C>      setbuf(char_type*, streamsize)
C>      {    return this; }
C>

C>(кто там что про виртуальные вызовы, кстати, говорил?)

Это абстрактный basic_streambuf, а то — stringbuf.

C>>>Дешевле можно, но только если весь клиентский код работает с конкретной реализацией потоков. Иначе в любом случае нужен где-то виртуальный вызов, и он есть, кстати.

MOP>>Ну так в C++ на все потоки одна реализация (sstream и fstream отличаются только косметически).
C>А stringbuf — виртуальный. Так что никуда не деться, виртуальные вызовы будут в любом случае.

Но не для каждой операции В/В.

MOP>>>>Это ООП наизнанку. Паттерн «стратегия».

C>>>Это не ООП наизнанку, это полный идиотизм дизайнеров. Можно было сделать намного проще и удобнее, с тем же оверхедом (один виртуальный вызов на операцию).
MOP>>Один виртуальный вызов на операцию — уже дорого. В вышеприведённых примерах возможно не будет ни одного виртуального вызова.
C>В вышеприведённом примере их как минимум 4 штуки только ДЛЯ ИНИЦИАЛИЗАЦИИ. Далее для каждой операции будет один-два виртуальных вызова + промежуточный слой + проверка локали.

Инициализация не считается (к тому же при инициализации виртуальных вызовов может и не быть — мы работаем с конкретными классами). А вот весь В/В внутри функции, куда передали поток, будет в буфер, без виртуальных вызовов. Может быть 1-2 вызова будет в самом конце (да и их можно избежать, если взять буфер с запасом).

Ну вот попробуйте, напишите тест и залогируйте виртуальные функции.
Re[5]: IO library
От: night beast СССР  
Дата: 15.11.11 17:41
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>>>Пока велосипедирую. Получается что-то вроде:

C>>>И манипуляторы к нему. Сейчас думаю как менее криво это пришпилить к стандартным потокам.
NB>>преобразовывать к stringstream?
C>Думаю насчёт тонкой обёртки в виде реализации istream/ostream. Оверхеда не избежать, но большая часть моего собственного кода легко переделывается на мои потоки. Я туда уже и форматированный вывод даже добавил, только сделаный не криво (как в стандартной библиотеке).

посмотри еще google::protobuf::io.
хотя свой велосипед наверно тоже нормальное решение.
Re[14]: IO library
От: Cyberax Марс  
Дата: 15.11.11 17:46
Оценка: 4 (1)
Здравствуйте, gegMOPO4, Вы писали:

C>>basic_stringbuf вылезает примерно в 100 строк!! Не считая ещё прилагающихся к нему basic_stringstream. Не буду я такой ублюдочный интерфейс даже трогать.

MOP>Это же библиотечная реализация, там большая часть — комментарии, тайпдефы и прочие пляски, ненужные конкретному типу. basic_stringstream же тривиален, содержит только конструктор и прокси-методы.
Ну приведи простейшую реализацию.

C>>(кто там что про виртуальные вызовы, кстати, говорил?)

MOP>Это абстрактный basic_streambuf, а то — stringbuf.
Стандартом это не гарантируется.

C>>А stringbuf — виртуальный. Так что никуда не деться, виртуальные вызовы будут в любом случае.

MOP>Но не для каждой операции В/В.
Для КАЖДОЙ операции.
Вызов read() у istream выливается в:
           _M_gcount = this->rdbuf()->sgetn(__s, __n);

rdbuf() в свою очередь, вызывает вот это:
virtual streamsize  xsgetn(char_type* __s, streamsize __n);

Упс.

Т.е. в STL не просто одно, а целых ДВА непрямых вызова — как минимум. Сначала непрямой вызов rdbuf(), потом виртуальный вызов xsgetn(). Это ещё не считая проверки всяких failbit и прочей гадости.

И это на КАЖДЫЙ ввод/вывод.

C>>В вышеприведённом примере их как минимум 4 штуки только ДЛЯ ИНИЦИАЛИЗАЦИИ. Далее для каждой операции будет один-два виртуальных вызова + промежуточный слой + проверка локали.

MOP>Инициализация не считается (к тому же при инициализации виртуальных вызовов может и не быть — мы работаем с конкретными классами).
Ещё как считается.

MOP>А вот весь В/В внутри функции, куда передали поток, будет в буфер, без виртуальных вызовов. Может быть 1-2 вызова будет в самом конце (да и их можно избежать, если взять буфер с запасом).

MOP>Ну вот попробуйте, напишите тест и залогируйте виртуальные функции.
Я уже протрассировал все вызовы. Мой код примерно в 20 раз быстрее на микротестах.
Sapienti sat!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.