C++ 使用boost::spirit解析任意精度整数

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是否适合读取包含任意长数字的二进制文件,

我想为任意整数创建boost::spirit::qi::语法。将整数存储到字符串只会让人感觉非常浪费内存,特别是当整数以二进制格式表示时。如何在结构中使用任意精度整数类(例如GMP或llvm::APInt)?

如果您有一个包含一系列任意长整数的文本文件,那么Qi肯定可以用于非常有效地将该文件解析为单个数字,以文本标记的形式表示。如何将这些代币转换为GMP数字取决于您,但我建议,库提供的通过文本输入数字的机制比您头脑中可能想到的任何机制都要优化


如果您询问Qi是否适合读取包含任意长数字的二进制文件,那么答案是肯定的-已经支持二进制解析器,请参见此处:。我不确定你的目标数学库的整数的格式,我猜你可以把这些原语链接在一起,直接读取数字的二进制表示。或者,您可以根据其中一个设计自己的解析器原语。

看起来Peter在这里提出了错误的问题

此后,我回答了他自己的问题,并将重点放在LLVM的APInt类型上

然而,在这个过程中,我——当然——展示了如何使用Boost多精度类型

为了更公正地回答这个问题,我将添加以下注释:

  • 从文件读取时,使用文件映射和原始
    char*
    ,而不是
    istream
    和流迭代器。我正好在这里的另一个回答线程中演示了加速:

    下面是如何优化阅读: coliru.stacked-crooked.com/a/0dcb8a05f12a08a5。现在一切都好了 ~1.28秒看起来很疯狂

    […]刮胡子的唯一方法 从解析它到s/double\uu/float\ug只需要几毫秒,但我不会 因为它从图形模型中删除了泛型

  • 通常,在使用boost multiprecision类型时,您会发现必须禁用表达式模板。另外,我认为真正的任意精度类型往往不能与
    int\u解析器
    一起很好地工作,但固定精度类型在我尝试时都能工作

  • 如果不需要,可以考虑解析所有数字。您可以“惰性地”解析某些文件,仅检测线边界或其他结构元素。然后,当需要时,您可以详细解析感兴趣的片段

    我有一个非常详细的答案,在一个内存映射文本文件上显示了这个(),您可以在没有任何内存开销的情况下对一个数千GB的文件进行二进制搜索,然后只解析相关区域:

    (包括生成测试数据)

    #定义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();
        }
    }