Компиляция строки и возврат ее в виде вектора - PullRequest
0 голосов
/ 23 октября 2018

Мой сервер получает некоторые запросы, компилирует ответ и отправляет его обратно.Иногда ответ - это файл, иногда HTML.Поэтому я определяю ответ следующим образом:

class ResponseData
{

public:
    bool operator== (const ResponseData & param) const { return id == param.id; }

public:
    RequestIdType id;
    RequestType type;
    std::vector<char> data;
};

Когда я компилирую ответ HTML, я использую std::stringstream.

std::vector<char> RequestHandler::createResponse( const RequestData * request ) const
{
    std::stringstream buffer;

    std::vector<char> result;
    result.assign( RESPONSE_HEADER, RESPONSE_HEADER + strlen( RESPONSE_HEADER ) );

    buffer << "<tr>";


    for( auto param : request->paramsMap )
    {
        buffer << "<tr><td>" << param.first << "</td><td>" << param.second << "</td></tr>\n";
    }

    buffer << "<\tr>";

    DEBUG_LOG_F << buffer.str();

    std::string str = buffer.str();

    result.insert( result.end(), str.begin(), str.end() );
    result.insert( result.end(), RESPONSE_FOOTER, RESPONSE_FOOTER + strlen( RESPONSE_FOOTER ) );


    return result;
}

Мне кажется, что копирование buffer в строку для добавления ее затем в вектор не является хорошей идеей.Как я могу сделать это более эффективно?

Ответы [ 3 ]

0 голосов
/ 23 октября 2018

Вы можете использовать std::istreambuf_iterator для копирования символов непосредственно из stringstream в вектор, например:

std::vector<char> sstreamToVector(std::stringstream& src)
{
    // make sure that "get" position is at the beginning and "put" is at the end of the stream
    src.seekg(0);
    src.seekp(0, std::ios::end);

    std::vector<char> dst;
    dst.reserve(src.tellp());
    std::copy(std::istreambuf_iterator<char>(src),
              std::istreambuf_iterator<char>(),
              std::back_inserter(dst));
    return dst;
}

str.tellp() возвращает количество символов, записанных в поток (p стойки)для «области размещения»), поэтому его можно использовать для выделения достаточного пространства в буфере.

0 голосов
/ 23 октября 2018

Я понимаю, что вам следует избегать перемещения char s между контейнерами.В этом простом случае не слишком сложно записать все в result напрямую:

auto result = accumulate(cbegin(request->paramsMap), cend(request->paramsMap), vector<char>{ '<', 't', 'r', '>', '<', '/', 't', 'r', '>' }, [](auto& init, const auto& i) {
    const char start[] = { '<', 't', 'r', '>', '<', 't', 'd', '>' };
    const char middle[] = { '<', '/', 't', 'd', '>', '<', 't', 'd', '>' };
    const char finish[] = { '<', '/', 't', 'd', '>', '<', '/', 't', 'r', '>' };

    init.insert(prev(cend(init), 5U), cbegin(start), cend(start));
    init.insert(prev(cend(init), 5U), i.first, next(i.first, strlen(i.first)));
    init.insert(prev(cend(init), 5U), cbegin(middle), cend(middle));
    init.insert(prev(cend(init), 5U), i.second, next(i.second, strlen(i.second)));
    init.insert(prev(cend(init), 5U), cbegin(finish), cend(finsh));
    return init;
} );

copy(cbegin(result), cend(result), ostream_iterator<char>{ DEBUG_LOG_F });
result.insert(cbegin(result), RESPONSE_HEADER, next(RESPONSE_HEADER, strlen(RESPONSE_HEADER)));
result.insert(cend(result), RESPONSE_FOOTER, next(RESPONSE_FOOTER, strlen(RESPONSE_FOOTER)));
return result;
0 голосов
/ 23 октября 2018

Просто используйте stringstream для всего. joe_chip демонстрирует, как копировать напрямую из stringstream.

std::stringstream buffer;

buffer << RESPONSE_HEADER;

for( auto param : request->paramsMap )
{
    buffer << "<tr><td>" << param.first << "</td><td>" << param.second << "</td></tr>\n";
    DEBUG_LOG_F << "<tr><td>" << param.first << "</td><td>" << param.second << "</td></tr>\n";
}

buffer << RESPONSE_FOOTER;

return sstreamToVector(buffer);
...