繁体   English   中英

如何合并/连接多个 boost::container::small_vector 并将值作为 boost::any_range 返回?

[英]How to merge/concatenate multiple boost::container::small_vector 's and return the values as a boost::any_range?

我有多个 boost::container::small_vector 存储在一个 std::vector 中,我想将存储在 small_vectors 中的所有值作为 boost::any_range 返回。 你有什么想法我该怎么做吗?

当然,您可以以非常低效的方式完成此操作,而无需自己编写更多代码:

    return boost::accumulate(_storage, R {},
        [](R&& accum, SV const& sv) { return boost::join(std::move(accum), sv); });

完整演示Live On Godbolt

#include <boost/container/small_vector.hpp>
#include <boost/range/any_range.hpp>
#include <boost/range/join.hpp>
#include <boost/range/numeric.hpp>

#include <fmt/ranges.h>

template <typename T>
struct MyData {
    using SV = boost::container::small_vector<T, 10>;
    using R = boost::any_range<T, boost::bidirectional_traversal_tag>;

    R all_view() const {
        return boost::accumulate(_storage, R {},
            [](R&& accum, SV const& sv) { return boost::join(std::move(accum), sv); });
    }

    std::vector<SV> _storage;
};

int main() {
    MyData<int> ints { { {1,2,3}, {4}, {5,6,7} } };

    fmt::print("ints: {}\n", ints.all_view());
}

印刷

ints: {1, 2, 3, 4, 5, 6, 7}
  • 优点:写得快

  • 缺点:

    • 需要最近的 boost 和编译器
    • 为大量子范围生成越来越糟糕的代码: 参见例如

    注意简单:我想 any_range 使用擦除来发挥它的魔力,这意味着你仍然(逻辑上)有一系列范围,除了现在它可能存储在范围对象的递归树中,每个节点都可能添加一个虚拟 function 调用,以及可能的动态分配。 (虚拟调用可能由非常智能的编译器优化,动态分配可能使用小对象缓冲区优化小范围(作为 QoI 问题),但这仍然限制了范围的可组合性。)

备择方案:

如果可以,请考虑具有yield_from的 RangeV3,它可以有效地展平范围,因为它不进行类型擦除。

或者,您可以编写自己的展平迭代器。 这是更多的工作,但可以通过 boost 进行管理,并将获得最佳的预期性能。

现场演示

#include <boost/container/small_vector.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/optional.hpp>

#include <fmt/ranges.h>

template <typename T>
struct MyData {
    using SV = boost::container::small_vector<T, 10>;
    std::vector<SV> _storage;

    struct const_iterator : boost::iterator_facade<const_iterator, T const,
                                boost::forward_traversal_tag> {
        using outer = typename std::vector<SV>::const_iterator;
        using inner = typename SV::const_iterator;

        const_iterator(const_iterator const&) = default;
        const_iterator& operator=(const_iterator const&) = default;

        const_iterator(outer f, outer l) : _outer(f), _last(l) {
            if (_outer != _last)
                _inner = _outer->begin();
            forward_transport();
        }

        const_iterator(outer f = {}) : const_iterator(f, f) {}

        bool equal(const_iterator const& other) const {
            return _outer == other._outer && _inner == other._inner;
        }

        void increment() {
            assert(_outer != _last && _inner != _outer->end());
            ++_inner;

            forward_transport();
        }

        decltype(auto) dereference() const {
            assert(_outer != _last);
            return *_inner;
        }

    protected:
        void forward_transport() { // skip over empty subrange(s)
            while (_outer != _last && _inner == _outer->end()) {
                ++_outer;

                if (_outer == _last)
                    _inner = {};
                else
                    _inner = _outer->begin();
            }
        }
        
        outer _outer, _last;
        inner _inner = {};
    };

    const_iterator begin() const { return {_storage.begin(), _storage.end()}; }
    const_iterator end()   const { return {_storage.end(),   _storage.end()}; }
};

int main() {
    MyData<int> ints { { {}, {}, {}, { 1, 2, 3 }, {}, {}, {}, {}, { 4 }, { 5, 6, 7 }, {} } };

    fmt::print("ints: {}\n", ints);
}

打印(再次/仍然):

ints: {1, 2, 3, 4, 5, 6, 7}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM