将字符串数据附加到 std::vector<std::byte>>
Append string data to std::vector<std::byte>>
我正在实现一个 HTTP 服务器,我遵循的 API 将原始响应数据定义为 std::vector<std::byte>>
。
我在我的代码中将 http 响应 headers 存储为 std::string
,有时我必须将它们写入原始响应数据,然后再发回。
问题是,我找不到从 std::string
到我的 std::vector<std::byte>>
的 write/append 数据的干净方式(通过干净的方式我的意思是不在字符串上循环并附加每个字符).
最好的方法是什么?
附带问题:从 std::vector<std::byte>>
读取字符串的最佳方法是什么?
你会想要像下面这样的东西。我意识到这仍然使用副本,但只有一个内存分配是昂贵的部分。
std::vector<std::byte> data;
std::string input;
...
data.reserve(data.size() + input.size());
std::copy(input.begin(), input.end(), std::back_inserter(data));
char
do 无法转换为std::byte
c++17。它被定义为范围枚举:
enum class byte : unsigned char {} ;
cppreference.com std::byte
A numeric value n
can be converted to a byte value using std::byte{n}
, due to C++17 relaxed enum class initialization rules.
您可以使用辅助函数或 lambda:
std::string headers;
std::vector<std::byte> response;
response.reserve(response.size() + headers.size()); // Optional
std::transform(headers.begin(), headers.end(), std::back_inserter(response),
[](unsigned char c) { return std::byte{c}; } // or `encode(c)`
);
您还可以调整 response
的大小并跳过 back_inserter
:
const auto response_size = response.size();
response.resize(response_size + headers.size());
std::transform(headers.begin(), headers.end(), std::next(response.begin(), response_size),
[](unsigned char c) { return std::byte{c}; }
);
实际上整个编译器会优化成类似std::copy
的东西。
或者只需将 std::byte
替换为 char
并使用 std::vector::insert()
或 std::copy()
。
只需使用范围-insert
重载 (#4):
void extend(std::vector<std::byte>& v, std::string const& s) {
auto bytes = reinterpret_cast<std::byte const*>(s.data());
v.insert(v.end(), bytes, bytes + s.size());
}
您可以将 char
读作 byte
,这是一个允许的别名。
首先从 gsl::span
或类似的开始。
template<class T>
struct span {
T* b =0, *e = 0;
T* begin() const { return b; }
T* end() const { return e; }
std::size_t size() const { return end()-begin(); }
bool empty() const { return end()==begin(); }
span( T* s, T* f ):b(s),e(f) {}
span( T* s, std::size_t len ):span(s, s+len) {}
template<class Uptr>
using is_compatible = std::is_convertible< Uptr*, T* >;
template<class R,
std::enable_if_t<!std::is_same<std::decay_t<R>, span>{}, bool> = true,
std::enable_if_t<is_compatible<decltype(std::declval<R&>().data())>{}, bool> = true
>
span( R&& r ):
span(r.data(), r.size())
{}
template<class U, std::size_t N,
std::enable_if_t<is_compatible<U*>{}, bool> = true
>
span( U(&arr)[N] ):span(arr, N) {}
};
现在我们有了 "possibly mutable view into contiguous T
s" 的抽象。
std::vector<std::byte> concat_string( std::vector<std::byte> lhs, span<char const> rhs ) {
lhs.reserve(lhs.size()+rhs.size());
lhs.insert( lhs.end(), (std::byte const*)rhs.begin(), (std::byte const*)rhs.end() );
return rhs;
}
这假定您不想嵌入 '[=14=]'
。
我正在实现一个 HTTP 服务器,我遵循的 API 将原始响应数据定义为 std::vector<std::byte>>
。
我在我的代码中将 http 响应 headers 存储为 std::string
,有时我必须将它们写入原始响应数据,然后再发回。
问题是,我找不到从 std::string
到我的 std::vector<std::byte>>
的 write/append 数据的干净方式(通过干净的方式我的意思是不在字符串上循环并附加每个字符).
最好的方法是什么?
附带问题:从 std::vector<std::byte>>
读取字符串的最佳方法是什么?
你会想要像下面这样的东西。我意识到这仍然使用副本,但只有一个内存分配是昂贵的部分。
std::vector<std::byte> data;
std::string input;
...
data.reserve(data.size() + input.size());
std::copy(input.begin(), input.end(), std::back_inserter(data));
char
do 无法转换为std::byte
c++17。它被定义为范围枚举:
enum class byte : unsigned char {} ;
cppreference.com std::byte
A numeric value
n
can be converted to a byte value usingstd::byte{n}
, due to C++17 relaxed enum class initialization rules.
您可以使用辅助函数或 lambda:
std::string headers;
std::vector<std::byte> response;
response.reserve(response.size() + headers.size()); // Optional
std::transform(headers.begin(), headers.end(), std::back_inserter(response),
[](unsigned char c) { return std::byte{c}; } // or `encode(c)`
);
您还可以调整 response
的大小并跳过 back_inserter
:
const auto response_size = response.size();
response.resize(response_size + headers.size());
std::transform(headers.begin(), headers.end(), std::next(response.begin(), response_size),
[](unsigned char c) { return std::byte{c}; }
);
实际上整个编译器会优化成类似std::copy
的东西。
或者只需将 std::byte
替换为 char
并使用 std::vector::insert()
或 std::copy()
。
只需使用范围-insert
重载 (#4):
void extend(std::vector<std::byte>& v, std::string const& s) {
auto bytes = reinterpret_cast<std::byte const*>(s.data());
v.insert(v.end(), bytes, bytes + s.size());
}
您可以将 char
读作 byte
,这是一个允许的别名。
首先从 gsl::span
或类似的开始。
template<class T>
struct span {
T* b =0, *e = 0;
T* begin() const { return b; }
T* end() const { return e; }
std::size_t size() const { return end()-begin(); }
bool empty() const { return end()==begin(); }
span( T* s, T* f ):b(s),e(f) {}
span( T* s, std::size_t len ):span(s, s+len) {}
template<class Uptr>
using is_compatible = std::is_convertible< Uptr*, T* >;
template<class R,
std::enable_if_t<!std::is_same<std::decay_t<R>, span>{}, bool> = true,
std::enable_if_t<is_compatible<decltype(std::declval<R&>().data())>{}, bool> = true
>
span( R&& r ):
span(r.data(), r.size())
{}
template<class U, std::size_t N,
std::enable_if_t<is_compatible<U*>{}, bool> = true
>
span( U(&arr)[N] ):span(arr, N) {}
};
现在我们有了 "possibly mutable view into contiguous T
s" 的抽象。
std::vector<std::byte> concat_string( std::vector<std::byte> lhs, span<char const> rhs ) {
lhs.reserve(lhs.size()+rhs.size());
lhs.insert( lhs.end(), (std::byte const*)rhs.begin(), (std::byte const*)rhs.end() );
return rhs;
}
这假定您不想嵌入 '[=14=]'
。