Можно ли использовать 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;    
}
Другие вопросы по тегам