C++ 使用boost::spirit解析任意精度整数
我想为任意整数创建boost::spirit::qi::语法。将整数存储到字符串只会让人感觉非常浪费内存,特别是当整数以二进制格式表示时。如何在结构中使用任意精度整数类(例如GMP或llvm::APInt)?如果您有一个包含一系列任意长整数的文本文件,那么Qi肯定可以用于非常有效地将该文件解析为单个数字,以文本标记的形式表示。如何将这些代币转换为GMP数字取决于您,但我建议,库提供的通过文本输入数字的机制比您头脑中可能想到的任何机制都要优化C++ 使用boost::spirit解析任意精度整数,c++,integer,boost-spirit-qi,arbitrary-precision,C++,Integer,Boost Spirit Qi,Arbitrary Precision,我想为任意整数创建boost::spirit::qi::语法。将整数存储到字符串只会让人感觉非常浪费内存,特别是当整数以二进制格式表示时。如何在结构中使用任意精度整数类(例如GMP或llvm::APInt)?如果您有一个包含一系列任意长整数的文本文件,那么Qi肯定可以用于非常有效地将该文件解析为单个数字,以文本标记的形式表示。如何将这些代币转换为GMP数字取决于您,但我建议,库提供的通过文本输入数字的机制比您头脑中可能想到的任何机制都要优化 如果您询问Qi是否适合读取包含任意长数字的二进制文件,
如果您询问Qi是否适合读取包含任意长数字的二进制文件,那么答案是肯定的-已经支持二进制解析器,请参见此处:。我不确定你的目标数学库的整数的格式,我猜你可以把这些原语链接在一起,直接读取数字的二进制表示。或者,您可以根据其中一个设计自己的解析器原语。看起来Peter在这里提出了错误的问题 此后,我回答了他自己的问题,并将重点放在LLVM的APInt类型上 然而,在这个过程中,我——当然——展示了如何使用Boost多精度类型 为了更公正地回答这个问题,我将添加以下注释:
char*
,而不是istream
和流迭代器。我正好在这里的另一个回答线程中演示了加速:
下面是如何优化阅读:
coliru.stacked-crooked.com/a/0dcb8a05f12a08a5。现在一切都好了
~1.28秒看起来很疯狂
[…]刮胡子的唯一方法
从解析它到s/double\uu/float\ug只需要几毫秒,但我不会
因为它从图形模型中删除了泛型
int\u解析器
一起很好地工作,但固定精度类型在我尝试时都能工作
#定义NDEBUG
#未定义调试
#包括
#包括
#包括
#包括
#包括
#包括
名称空间io=boost::iostreams;
名称空间qi=boost::spirit::qi;
模板
结构文本\u多重\u查找{
文本多重查找(字符常量*开始,字符常量*结束)
:_map_begin(开始),
_地图(完)
{
}
私人:
友元结构迭代器;
枚举:字符{nl='\n'};
使用rawit=char const*;
rawit(映射)开始,映射(映射)结束;;
rawit起始线(rawit)常数{
while(it>\u map\u begin)if(*--it==nl)返回+1;
断言(它==\u映射\u开始);
归还它;
}
拉维特线末端(拉维特)常数{
如果(*it++==nl),则返回(it<\u map\u end);
断言(它==\u映射\u结束);
归还它;
}
公众:
结构值\类型最终{
拉维特乞求,结束;
钥匙;
价值观;
boost::string_ref str()常量{return{beg,size_t(end beg)};}
};
结构迭代器:boost::迭代器{
迭代器(text_multi_lookup const&d,rawit):_region(&d),_data{it,nullptr,Key{},Value{}{
断言(_data.beg==_区域->_行(_data.beg)的开始);
}
私人:
朋友文本查找;
文本多查找常量*区域;
值类型可变数据;
void sure_parsed()常量{
如果(!\u data.end)
{
断言(_data.beg==_区域->_行(_data.beg)的开始);
自动b=_data.beg;
_data.end=\u区域->结束\u行(\u data.beg)的\u;
如果(!qi::短语_parse)(
b、 _data.end,
qi::auto\u>>qi::auto\u>>qi::eoi,
齐:空间,
_data.key,_data.value))
{
std::cerr我在发布我自己的帖子后确实找到了这封邮件,我应该删除我的邮件并给这封邮件发奖金,但这封邮件也很好。@Peter啊,这很有道理。奖金是好的报应。谢谢你的关心!
#define NDEBUG
#undef DEBUG
#include <boost/iostreams/device/mapped_file.hpp>
#include <boost/utility/string_ref.hpp>
#include <boost/optional.hpp>
#include <boost/spirit/include/qi.hpp>
#include <thread>
#include <iomanip>
namespace io = boost::iostreams;
namespace qi = boost::spirit::qi;
template <typename Key, typename Value>
struct text_multi_lookup {
text_multi_lookup(char const* begin, char const* end)
: _map_begin(begin),
_map_end(end)
{
}
private:
friend struct iterator;
enum : char { nl = '\n' };
using rawit = char const*;
rawit _map_begin, _map_end;
rawit start_of_line(rawit it) const {
while (it > _map_begin) if (*--it == nl) return it+1;
assert(it == _map_begin);
return it;
}
rawit end_of_line(rawit it) const {
while (it < _map_end) if (*it++ == nl) return it;
assert(it == _map_end);
return it;
}
public:
struct value_type final {
rawit beg, end;
Key key;
Value value;
boost::string_ref str() const { return { beg, size_t(end-beg) }; }
};
struct iterator : boost::iterator_facade<iterator, boost::string_ref, boost::bidirectional_traversal_tag, value_type> {
iterator(text_multi_lookup const& d, rawit it) : _region(&d), _data { it, nullptr, Key{}, Value{} } {
assert(_data.beg == _region->start_of_line(_data.beg));
}
private:
friend text_multi_lookup;
text_multi_lookup const* _region;
value_type mutable _data;
void ensure_parsed() const {
if (!_data.end)
{
assert(_data.beg == _region->start_of_line(_data.beg));
auto b = _data.beg;
_data.end = _region->end_of_line(_data.beg);
if (!qi::phrase_parse(
b, _data.end,
qi::auto_ >> qi::auto_ >> qi::eoi,
qi::space,
_data.key, _data.value))
{
std::cerr << "Problem in: " << std::string(_data.beg, _data.end)
<< "at: " << std::setw(_data.end-_data.beg) << std::right << std::string(_data.beg,_data.end);
assert(false);
}
}
}
static iterator mid_point(iterator const& a, iterator const& b) {
assert(a._region == b._region);
return { *a._region, a._region->start_of_line(a._data.beg + (b._data.beg -a._data.beg)/2) };
}
public:
value_type const& dereference() const {
ensure_parsed();
return _data;
}
bool equal(iterator const& o) const {
return (_region == o._region) && (_data.beg == o._data.beg);
}
void increment() {
_data = { _region->end_of_line(_data.beg), nullptr, Key{}, Value{} };
assert(_data.beg == _region->start_of_line(_data.beg));
}
};
using const_iterator = iterator;
const_iterator begin() const { return { *this, _map_begin }; }
const_iterator end() const { return { *this, _map_end }; }
const_iterator cbegin() const { return { *this, _map_begin }; }
const_iterator cend() const { return { *this, _map_end }; }
template <typename CompatibleKey>
const_iterator lower_bound(CompatibleKey const& key) const {
auto f(begin()), l(end());
while (f!=l) {
auto m = iterator::mid_point(f,l);
if (m->key < key) {
f = m;
++f;
}
else {
l = m;
}
}
return f;
}
template <typename CompatibleKey>
const_iterator upper_bound(CompatibleKey const& key) const {
return upper_bound(key, begin());
}
private:
template <typename CompatibleKey>
const_iterator upper_bound(CompatibleKey const& key, const_iterator f) const {
auto l(end());
while (f!=l) {
auto m = iterator::mid_point(f,l);
if (key < m->key) {
l = m;
}
else {
f = m;
++f;
}
}
return f;
}
public:
template <typename CompatibleKey>
std::pair<const_iterator, const_iterator> equal_range(CompatibleKey const& key) const {
auto lb = lower_bound(key);
return { lb, upper_bound(key, lb) };
}
};
#include <iostream>
int main() {
io::mapped_file_source map("input.txt");
text_multi_lookup<double, unsigned int> tml(map.data(), map.data() + map.size());
auto const e = tml.end();
for(auto&& line : tml)
{
std::cout << line.str();
auto er = tml.equal_range(line.key);
if (er.first != e) std::cout << " lower: " << er.first->str();
if (er.second != e) std::cout << " upper: " << er.second->str();
}
}