Можно ли использовать Boost.Format с предварительно выделенным буфером?
Мне было интересно, поддерживает ли Boost.Format использование буфера фиксированной ширины / предварительно выделенного в качестве вывода вместо динамического буфера, управляемого самой библиотекой?
То есть обычно вы делаете:
boost::format myfmt("arg1: %1% / arg2: %2%");
// e.g.:
cout << (myfmt % 3.14 % 42);
// or
string s = boost::str( myfmt % "hey!" % "there!");
поэтому Boost:Format lib автоматически позаботится о выделении достаточного места и управлении "буфером вывода" для вас.
Мне было интересно, есть ли способ использовать предопределенный нединамический буфер с Boost.Format, то есть что-то вроде:
const size_t buf_sz = 512;
char big_enough[buf_sz];
boost::format myfmt("arg1: %1% / arg2: %2%");
myfmt.attach_buffer(big_enough, buf_sz);
myfmt % "hey!" % "there!"
// big_enough buffer now contains the result string
Я знаю, что мог бы просто просмотреть примеры, документы и источники, но не считая недостатка времени. (и сама возможность чего-то упустить) было бы интересно узнать: если это невозможно, было бы здорово, если бы кто-то мог объяснить почему (если есть / есть конкретные причины) - было ли это преднамеренно? разве это не соответствует API? ...?
Отказ от ответственности: Этот вопрос не о производительности!
1 ответ
Начальная идея
Глядя на источник, кажется, что вы можете использовать свой собственный распределитель, который затем используется внутренним потоком (internal_streambuf_t
) из boost::format
, Это было бы достаточно для вашего случая?
Например, вы можете использовать что-то вроде libstdC++ array_allocator
к несчастью boost::format
также использует пару std::vector
которые не используют пользовательский распределитель, который может быть проблемой в вашем случае?
Как boost::format
работает
Я заглянул в источник boost::format
и вот как это работает (описано ниже str()
, <<
звонит либо str()
или использует стандарт std::ostream
вещи):
- класс format хранит все аргументы и форматную строку отдельно, иногда используя пользовательский распределитель, иногда используя распределитель по умолчанию
- когда
str()
называется это создает новыйstd::string
и делает его достаточно большим для результата, используя пользовательский распределитель - затем он добавляет все аргументы и фрагменты статической строки из строки формата в строку результата
- наконец, он возвращает строку результата по значению
Таким образом, строка окончательного результата не сохраняется в классе формата, а создается при необходимости.
Таким образом, даже если вы можете найти расположение строки результата при использовании пользовательского распределителя, она доступна только после / во время вызова str()
, Это должно объяснить, почему это невозможно: отформатированный результат никогда не сохраняется в "выходном буфере" в классе.
Почему это работает так
Почему они так поступили, я не знаю. Я думаю, это потому, что вы можете построить результат только после того, как все аргументы известны, это тратит пространство на хранение результата, и вам, вероятно, нужен только один раз для данной комбинации формат / аргумент. Поэтому его создание при необходимости не приводит к дополнительной работе, поскольку обычно str()
вызывается только один раз.
Решения
- Создайте некоторую обертку вокруг
str()
или же<<
и скопируйте результат в свой фиксированный буфер - Использовать
stream_buffer
"поток" строки в буфер (см. пример ниже) - Наследуй класс и добавь свой
str()
функция, которая сохраняет результат в фиксированном буфере.
Возможное решение с использованием boost:: iostreams (протестировано):
#include <iostream>
#include <boost/format.hpp>
#include <boost/iostreams/stream.hpp>
int main()
{
char buffer[100];
boost::iostreams::stream<boost::iostreams::array_sink>
stream(buffer, sizeof(buffer));
stream << (boost::format("arg1 = %1%") % 12.5);
stream << '\0'; // make sure buffer contains 0-terminated string
std::cout << buffer << std::endl;
}