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

时间:2012-09-18 16:33:23

标签: c++ integer boost-spirit-qi arbitrary-precision

我想为任意整数创建boost :: spirit :: qi :: grammar。将整数存储到字符串只是感觉可怕的内存浪费,特别是当整数以二进制格式表示时。我怎么能在结构中使用任意精度整数类(例如GMP或llvm :: APInt)?

2 个答案:

答案 0 :(得分:1)

如果你有一个包含一系列任意长整数的文本文件,那么肯定可以使用Qi非常有效地将该文件解析为单个数字,以文本标记的形式呈现。如何将这些令牌转换为GMP号码取决于你,但我建议库提供的通过文本输入数字的机制比你可能想到的任何东西都更加优化。< / p>

如果你问Qi是否可以适应读取包含任意长数的二进制文件,那么答案是肯定的 - 已经支持二进制解析器,请参见此处:http://www.boost.org/doc/libs/1_48_0/libs/spirit/doc/html/spirit/qi/reference/binary.html。我不确定你的目标数学库的整数的格式是我可以将这些基元链接在一起直接读取数字的二进制表示。或者,您可以根据其中一个来设计自己的解析器原语。

答案 1 :(得分:1)

看起来彼得在这里找错了问题。

我回答了他自己的问题 Parse arbitrary precision numbers with Boost spirit,该问题确实关注 LLVM 的 APInt 类型。

但是在这个过程中,我 - 当然 - 展示了如何使用 Boost 多精度类型。

我将添加以下注释以更公正地说明这个问题的重点:

  1. 从文件读取时,使用文件映射和原始 char* 而不是 istream 和流迭代器。我刚好在另一个回答线程中展示了它的加速:comment link

    <块引用>

    所以这里是如何优化阅读: coliru.stacked-crooked.com/a/0dcb8a05f12a08a5。现在一切都在 ~1.28s 看起来疯狂优化

    [...] 唯一的方法来剃掉一个 解析它的几毫秒 s/double_/float_/g 但我不会 因为它从 Graph 模型中删除了通用性。 – sehe 3 hours ago

  2. 通常在使用 boost 多精度类型时,您会发现必须禁用表达式模板。此外,我认为真正的任意精度类型往往不适用于 int_parser<>,但我尝试时固定精度类型都可以。

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

    我有一个非常详细的答案在内存映射文本文件中显示了这个 (Using boost::iostreams::mapped_file_source with std::multimap),您可以在其中对一个多 GB 的文件进行二进制搜索而无需任何内存开销,然后只解析相关的区域:

    Live On Coliru(包括生成测试数据)

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