从标准::字符串到标准::矢量<bool>的快速转换
Fast conversion from std::string to std::vector<bool>
编辑:我将原始问题留在下面,但转换并不像我声称的那么慢。我的原始程序中有一个错误,导致调用函数的输入比我预期的要长得多。事实上,从string
转换为vector
只需要大约 1.5 倍的时间,然后才能转换其他方式。
我需要将字符串转换为vector<bool>
.但是,转换非常缓慢。我知道vector<bool>
是矢量的专业化。我尝试改用vector<char>
,但这同样慢。
这是我的代码:
std::vector<bool> frombytes(const std::string &bytes)
{
std::vector<bool> output;
for (unsigned int i = 0; i < bytes.length(); i++)
{
unsigned char byte = bytes[i];
for (unsigned int j = 0; j < 8; j++)
{
output.push_back(byte >> (7 - j) & 1);
}
}
}
我在想,也许通过一次写入 8 位,我可以使它更快。但是,我想不出一种方法来做到这一点。任何建议都会有所帮助。谢谢!
更多信息:
- 我试过
vector::reserve
,但这并没有太大区别。 - 我正在使用带有"
-O3
"标志的g++编译程序。
我不确定这种转换是否必要。您可以使用简单的访问器函数来获取单个位,并且可以编写简单的自定义迭代器,这些迭代器将字符串中的位公开为单独的布尔值。这完全回避了转换成本。转换是非常浪费的,因为在内部,vector<bool>
通常将实现为无符号字符或整数的向量,并使用特殊的访问器来调整其中的位。vector<bool>
和std::string
中数据的内存表示形式很可能是相同的,但位和/或字节顺序可能除外。因此,如果您似乎非常关心性能,那么跳过整个喧嚣是最有意义的。
访问器非常简单:
bool getBit(size_t index, const std::string &str)
{
assert(index/8 < str.size());
return (str[index/8] >> (index%8)) & 1;
}
void setBit(size_t const index, bool const val, std::string &str)
{
assert(index/8 < str.size());
char c = str[index/8];
c &= ~(1 << (index%8));
c |= char(val) << (index % 8);
str[index/8] = c;
}
如果要将字符串迭代为位,可以使用以下迭代器适配器(未经测试(:
template <typename Container>
class const_bit_iterator {
using c_value_type = const Container::value_type;
using iterator = Container::const_iterator;
static constexpr size_t modulus = 8u * sizeof(c_value_type );
size_t index = 0;
iterator it = {};
constexpr c_value_type bitmask() const { return c_value_type (1) << (index % modulus); }
public:
using value_type = const bool;
struct end_tag_t {};
static constexpr end_tag_t end_tag = {};
explicit bit_iterator(const Container &container) : it(container.begin()) {}
explicit bit_iterator(end_tag_t, const Container &container) :
index(modulus * container.size()), it(container.end()) {}
bool operator*() const { return get(); }
bool get() const { return (*it) & bitmask(); }
bit_iterator &operator++() {
++ index;
if (!(index % modulus)) ++ it;
return *this;
}
bit_iterator operator++(int) {
auto it = *this;
++ *this;
return it;
}
bit_iterator &operator--() {
-- index;
if ((index % modulus) == (modulus - 1)) -- it;
return *this;
}
bit_iterator operator--(int) {
auto it = *this;
-- *this;
return it;
}
bool operator==(const bit_iterator &o) const { return index == o.index; }
bool operator!=(const bit_iterator &o) const { return index != o.index; }
bool operator<(const bit_iterator &o) const { return index < o.index; }
};
template <typename Container>
class const_bit_adapter
{
const Container &ref;
public:
const_bit_adapter(const Container &container) : ref(container) {}
const_bit_iterator begin() const { return const_bit_iterator(ref); }
const_bit_iterator end() const { return const_bit_iterator(const_bit_iterator::end_tag, ref); }
};
template <typename Container>
const_bit_adapter<Container> as_const_bits(const Container &container)
{ return {container}; }
template <typename Container>
const_bit_adapter<Container> as_bits(const Container &container)
{ return {container}; }
使用示例:
std::vector<int> bits(32);
size_t n = 0;
for (bool b : as_const_bits(bits))
++n;
assert(n == bits.size() * 8u * sizeof(decltype(bits)::value_type));
我尝试了几种不同的方法,即使用表格和开关来使其更快。以下是结果:
- 使用开关的结果
- 使用表格的结果
由于快速工作台中的字符限制,结果是分开的。
- 使用开关和返回
std::array
几乎比原始版本快1.8
倍。 - 使用表格的速度比原始版本快
1.6 - 1.7
倍。 - 使用
std::vector<bool>
比使用std::vector<unsigned char>
略慢
用于生成表和开关的代码(稍作修改(:
std::vector<bool> frombytes(int byte)
{
std::vector<bool> output;
for (unsigned int j = 0; j < 8; j++)
{
output.push_back(byte >> (7 - j) & 1);
}
return output;
}
int main()
{
std::cout << "{n";
for (int i = 0; i <= 255; i++) {
auto bits = frombytes(i);
/* std::cout << "case " << i <<":n"; */
std::cout << " {";
int cnt = 0;
for (auto b : bits) {
cnt++;
if (cnt == 8)
std::cout << b;
else
std::cout << b << ", ";
}
std::cout << "},n";
}
std::cout << "n};n";
return 0;
}
相关文章:
- 如何正确将字符串转换为标准::时间::system_clock::time_point?
- 如何在 C++11 中将标准::字符串转换为标准::u32字符串?
- 从标准::字符串到标准::矢量<bool>的快速转换
- 将手写循环转换为标准库调用
- C++ - 转换标准::浮点数组的字符串
- 如何将 tbb concurrent_hash_map转换为常规标准::地图?
- 从常量字符*、字符*参数到标准::字符串的直接转换接口
- 热将标准::__cxx11::字符串转换为标准::字符串
- C++17 编解码器在将标准::字符串转换为标准::字符串时抛出"bad conversion"
- 如何将 C 数组转换为标准::initializer_list?
- 从双秒到标准::时间:steady_clock::d的简短转换?
- 是参考转换是标准转换
- STL标准::转换
- 重载标准::转换算法
- 标准::转换的功能版本
- 标准::转换中的 [] const_iterator::value_type 是什么意思
- 通过初始标准转换序列区分用户定义的转换序列
- 提升::转换与标准::转换
- 用户定义转换的第二个标准转换序列
- 标准::转换的泛化