为固定大小的多索引多态容器提升多索引

时间:2012-05-31 02:16:45

标签: c++ boost lru boost-multi-index

仍在深入研究C ++ / boost,欢迎任何意见/反馈。

我正在玩boost :: unordered_maps并使用形状创建了一个多态的例子,关于我头脑的时间 缠绕在那里(大部分)我偶然发现了来自boost multi_index的mru示例。 http://www.boost.org/doc/libs/1_46_1/libs/multi_index/example/serialization.cpp

那时我想。嗯,一个固定大小的多索引多态容器,它将丢弃基于的值 LRU,听起来很疯狂,没有实现。

    #include <boost/multi_index_container.hpp>
    #include <boost/multi_index/hashed_index.hpp>
    #include <boost/multi_index/identity.hpp>
    #include <boost/multi_index/sequenced_index.hpp>
    #include <boost/shared_ptr.hpp>
    #include <boost/tuple/tuple.hpp>
    #include "boost/tuple/tuple_comparison.hpp"

    enum shape_returns {
        SHAPE_ERROR = -1,
        SHAPE_OK = 0
    };

    // coordinates
    typedef boost::tuples::tuple<int, int, int> ShapeKey;

    class Shape {
    public:
        Shape() : pos() {}
        ~Shape() {}

        virtual int draw() { return SHAPE_ERROR; }

        ShapeKey pos;
    };
    typedef boost::shared_ptr<Shape> Shape_ptr;

    class Circle : public Shape {
    public:
        Circle() {}
        ~Circle() {}

        int radius;

        virtual int draw() { /* draw stuff */ return SHAPE_OK; }
    };
    typedef boost::shared_ptr<Circle> Circle_ptr;

    class Square : public Shape {
    public:
        Square() {}
        ~Square() {}

        int len;

        virtual int draw() { /* draw stuff */ return SHAPE_OK; }
    };
    typedef boost::shared_ptr<Square> Square_ptr;

    using namespace boost::multi_index;

    // multi index tags
    struct seq  {};
    struct hash {};

    class ShapesLRU {
        typedef boost::multi_index::multi_index_container<
          Shape_ptr,
          boost::multi_index::indexed_by<
            boost::multi_index::sequenced<boost::multi_index::tag<seq> >,
            boost::multi_index::hashed_unique<
              boost::multi_index::tag<hash>,
              boost::multi_index::identity<Shape_ptr>
            >
          >
        > shapes_list;

    public:
        typedef typename shapes_list::iterator iterator;
        typedef typename boost::multi_index::index<shapes_list, seq>::type seq_index;
        typedef typename boost::multi_index::index<shapes_list, hash>::type hashed_index;

        ShapesLRU (std::size_t max) : max_shapes(max) {}
        ~ShapesLRU() {}

        void insert(const Shape_ptr item)
        {
            std::pair<typename shapes_list::iterator, bool> ret = shapes.push_front(item);

            if (!ret.second) {
                // new item may be different
                erase(item->pos);
                ret = shapes.push_front(item);
            } else if (shapes.size() > max_shapes) {
                shapes.pop_back();
            }
        }

        typename shapes_list::iterator begin() { return shapes.begin(); }
        typename shapes_list::iterator end() { return shapes.end(); }

        typename hashed_index::iterator hash_begin() { return shapes.get<hash>().begin(); }
        typename hashed_index::iterator hash_end() { return shapes.get<hash>().end(); }

        typename hashed_index::iterator find(const ShapeKey &key)
        {
            Shape_ptr tmp(new Shape());
            tmp->pos = key;

            // XXX why compiler error w/o "using namespace boost::multi_index"
            return shapes.get<hash>().find(tmp);
        }

        void erase(const ShapeKey &key)
        {
            typename hashed_index::iterator itr = find(key);
            // XXX why compiler error w/o "using namespace boost::multi_index"
            shapes.get<hash>().erase(itr);
        }

    private:
        // The multi-indexed data store
        shapes_list shapes;

        // The size of the data store
        std::size_t max_shapes;
    };

    inline std::size_t
    hash_value(const Shape_ptr shape)
    {
        std::size_t seed = 0;

        boost::hash_combine(seed, shape->pos.get<0>());
        boost::hash_combine(seed, shape->pos.get<1>());
        boost::hash_combine(seed, shape->pos.get<2>());

        return seed;
    }

    int
    main()
    {
        ShapesLRU shapes(10);

        Circle_ptr cptr1(new Circle());
        ShapeKey pos1(1, 1, 1);
        cptr1->pos = pos1;
        cptr1->radius = 1;

        Circle_ptr cptr2(new Circle());
        ShapeKey pos2(2, 2, 2);
        cptr2->radius = 2;
        cptr2->pos = pos2;

        shapes.insert(cptr1);

        ShapesLRU::hashed_index::iterator itr = shapes.find(pos1);

        return 0;
    }

经过很多工作后,我仍然留下了以下问题。

    insert()中的
  1. 有一种方法可以从序列中获取hashed_unique迭代器 iterator所以我可以直接调用erase?

  2. 有没有更好的方法实现查找?如果我能找到这样的话会很好 一个boost :: unordered_map只使用键,而不是必须创建一个虚拟 形状只是为了查找。

  3. get&lt;&gt;的正确路径是什么? (参见代码中的XXX评论)我尝试了一切我正确的事情,然后开始尝试随机废话,没有任何东西被淘汰。

  4. 我真的很喜欢[]运算符,但我认为这是一个方法...... 形状[cptr1-&gt; pos] = cptr1;

  5. 如何从我的hash_index :: iterator中获取项目(或者通常理解这一点),打印它当然没有帮助......

  6. p itr $ 1 = {,std :: allocator&gt; &GT; &gt;,boost :: multi_index :: detail :: bucket_array&gt; &GT; &gt;,boost :: shared_ptr,long,boost :: shared_ptr const *,boost :: shared_ptr const&amp;&gt;&gt; = {,std :: allocator&gt; &GT; &gt;,boost :: multi_index :: detail :: bucket_array&gt; &GT; &gt;,boost :: shared_ptr const *,boost :: iterator,long,boost :: shared_ptr const *,boost :: shared_ptr const&amp;&gt; &GT;&GT; = {,std :: allocator&gt; &GT; &gt;,boost :: multi_index :: detail :: bucket_array&gt; &GT; &gt;,boost :: shared_ptr const *,boost :: iterator,long,boost :: shared_ptr const *,boost :: shared_ptr const&amp;&gt; &GT;&GT; = {,std :: allocator&gt; &GT; &gt;,boost :: multi_index :: detail :: bucket_array&gt; &GT; &gt;,boost :: incrementable,std :: allocator&gt; &GT; &gt;,boost :: multi_index :: detail :: bucket_array&gt; &GT; &gt;,boost :: dereferenceable,std :: allocator&gt; &GT; &gt;,boost :: multi_index :: detail :: bucket_array&gt; &GT; &gt;,boost :: shared_ptr const *,boost :: iterator,long,boost :: shared_ptr const *,boost :: shared_ptr const&amp;&gt; &GT; &GT; &GT;&GT; = {,std :: allocator&gt; &GT; &gt;,boost :: multi_index :: detail :: bucket_array&gt; &GT; &gt;,boost :: dereferenceable,std :: allocator&gt; &GT; &gt;,boost :: multi_index :: detail :: bucket_array&gt; &GT; &gt;,boost :: shared_ptr const *,boost :: iterator,long,boost :: shared_ptr const *,boost :: shared_ptr const&amp;&gt; &GT; &GT;&GT; = {,std :: allocator&gt; &GT; &gt;,boost :: multi_index :: detail :: bucket_array&gt; &GT; &gt;,boost :: shared_ptr const *,boost :: iterator,long,boost :: shared_ptr const *,boost :: shared_ptr const&amp;&gt; &GT;&GT; = {,long,boost :: shared_ptr const *,boost :: shared_ptr const&amp;&gt;&gt; = {,long,boost :: shared_ptr const *,boost :: shared_ptr const&amp;&gt;&gt; = {,long,boost :: shared_ptr const *,boost :: shared_ptr const&amp;&gt;&gt; = {},},},},},},},},},node = 0x60a010,buckets = 0x7fffffffdd88}

1 个答案:

答案 0 :(得分:1)

  在insert()中有一种从中获取hashed_unique迭代器的方法   序列迭代器所以我可以直接调用erase?

请参阅iterator projection

  

有没有更好的方法实现查找?如果我能做到这一点会很好   使用密钥,而不是使用密钥,发现像boost :: unordered_map   为查找创建一个虚拟形状。

首先,我认为您当前的实现是错误的:您的哈希索引基于Shape_ptr平等,这不是您所追求的 - 您希望基于Shape::ShapeKey的相等性。为了得到这个,只需将索引重新定义为

boost::multi_index::hashed_unique<
  boost::multi_index::tag<hash>,
  boost::multi_index::member<Shape,ShapeKey,&Shape::pos>
>

要实现此功能,您必须实施ShapeKey的哈希,作为练习留下:-)现在实施find就像

一样简单
hashed_index::iterator find(const ShapeKey &key)
{
    return shapes.get<hash>().find(key);
}
  

get&lt;&gt;的正确途径是什么? (见代码中的XXX评论)我试过了   一切我都是正确的,然后开始尝试随机废话,   什么都没有被淘汰。

我看不出为什么你的语法不起作用。它应该。

  

我真的很喜欢[]运算符,但我认为这是一个方法......   形状[cptr1-&gt; pos] = cptr1;

Boost.MultiIndex中的索引是在std::setstd::unordered_set而不是std::mapstd::unordered_map之后建模的(出于根本原因,我们无需在此讨论。)但请考虑一下map<T,Q>几乎是set<mutable_pair<T,Q>>,其中mutable_pair是一对结构,其第二个成员是mutable。你可以利用这个等价来绘制Boost.MultiIndex构建类似地图的结构。

  

如何从我的hash_index :: iterator中获取项目(或者通常理解这一点),打印它当然没有帮助......

“打印”是什么意思?