查找 boost multi index Tag to index 和 index 数量

Find boost multi index Tag to index and number of indices

我有一个模板 class(CrMultiIndex),它接收作为模板参数的 boost multi index(GlobalHash) 的定义。

我需要:

  1. 根据使用的索引向我的模板添加统计信息class。 所以我需要一种方法来在初始化时使用现有索引的数量调整向量(m_StatsByIndex)的大小。
  2. 我仍然希望用户根据标签而不是索引号进行搜索。 所以我需要一种从标签转换为索引号的方法,这样我就可以根据向量中的索引更新向量中的统计信息。

我有模板class

template <typename KeysType, typename MultiIndexType>
class CrMultiIndex
{

std::vector<SrStatisticsByIndex> m_StatsByIndex;

public:
MultiIndexType *m_pMultiIndex=NULL; 

CrMultiIndex()
{
    m_pMultiIndex = new MultiIndexType(typename 
    MultiIndexType::ctor_args_list());
}

这里是boost多索引容器的定义:

typedef boost::multi_index::multi_index_container<
  CrUsersKeys,
  UsersKey_hash_indices/*,
  bip::allocator<CrUsersKeys,bip::managed_shared_memory::segment_manager>*/
> GlobalHash;

具有根据标签搜索功能

template <typename TagType,typename SearchingKey>
typename MultiIndexType::template index<TagType>::type::iterator  
GetIteratorBy(SearchingKey & key)
{
    return  m_pMultiIndex->template get<TagType>().find(key) ;
}

代码位于 http://coliru.stacked-crooked.com/a/d97195a6e4bb7ad4

您需要查询嵌入式索引类型列表:

typedef typename MultiIndexType::index_type_list::size NumberOfIndexes;

template <typename Tag> constexpr static size_t IndexOfTag() {
    namespace mpl = boost::mpl;
    using tl = typename MultiIndexType::index_type_list;
    using B  = typename mpl::begin<tl>::type;
    using helper = typename MultiIndexType::template index<Tag>;
    static_assert(helper::index_found, "index not found");
    auto N = mpl::distance<B, typename helper::iter>::value;
    return N;
}

或者,一路使用Boost Mpl:

typedef typename MultiIndexType::index_type_list::size NumberOfIndexes;

template <typename Tag> constexpr static size_t IndexOfTag() {
    namespace mpl = boost::mpl;
    using tl = typename MultiIndexType::index_type_list;
    using B  = typename mpl::begin<tl>::type;
    using E  = typename mpl::end<tl>::type;
    using It = typename mpl::find_if<tl, bmi::detail::has_tag<Tag> >::type;
    static_assert(not std::is_same<E, It>(), "index not found");
    auto N = mpl::distance<B, It>::value;
    return N;
}

你可以这样使用它:

template <typename TagType, typename SearchingKey>
    typename MultiIndexType::template index<TagType>::type::iterator 
GetIteratorBy(SearchingKey &key) {
    auto& idx   = m_pMultiIndex.template get<TagType>();
    auto& stats = GetStats<TagType>();

    auto it = idx.find(key);
    ++(it == idx.end()? stats.searchedNotFound : stats.searchedSuccessfully);

    return it;
}

演示

注意代码已被简化:

Live On Coliru

#include <iostream>
#include <boost/multi_index/member.hpp>           // for member
#include <boost/multi_index/hashed_index.hpp>     // for hashed_unique
#include <boost/multi_index/ordered_index.hpp>    // for ordered_non_unique
#include <boost/multi_index_container.hpp>        // for multi_index_container

namespace bmi = boost::multi_index;

struct SrStatisticsByIndex {
    int deleted;
    int searchedSuccessfully;
    int searchedNotFound;
};

template <typename MultiIndexType, typename ValueType = typename MultiIndexType::value_type> 
class CrMultiIndex {

    typedef typename MultiIndexType::index_type_list::size NumberOfIndexes;

    template <typename Tag> constexpr static size_t IndexOfTag() {
        using tl = typename MultiIndexType::index_type_list;
        using B  = typename boost::mpl::begin<tl>::type;
        using helper = typename MultiIndexType::template index<Tag>;
        static_assert(helper::index_found, "index not found");

        return boost::mpl::distance<B, typename helper::iter>::value;
    }

  public:
    MultiIndexType m_pMultiIndex;

    template <typename Tag> SrStatisticsByIndex& GetStats()
        { return m_StatsByIndex.at(IndexOfTag<Tag>()); }

    template <typename Tag> SrStatisticsByIndex const& GetStats() const
        { return m_StatsByIndex.at(IndexOfTag<Tag>()); }

    // All the protected function are non locking function
    template <typename TagType, typename SearchingKey>
        typename MultiIndexType::template index<TagType>::type::iterator 
    GetIteratorBy(SearchingKey &key) {
        auto& idx   = m_pMultiIndex.template get<TagType>();
        auto& stats = GetStats<TagType>();

        auto it = idx.find(key);
        ++(it == idx.end()? stats.searchedNotFound : stats.searchedSuccessfully);

        return it;
    }

    void Insert(ValueType const &key) {
        std::cout << (m_pMultiIndex.insert(key).second? "success":"failed") << std::endl;
    }

  private:
    std::vector<SrStatisticsByIndex> m_StatsByIndex { NumberOfIndexes() };
};

class CrUsersValue {
    int val1;
    int val2;
};

class CrUsersKeys {
  public:
    int IMSI;
    int TIMESTAMP;
    CrUsersValue val;
};

typedef boost::multi_index::multi_index_container<
        CrUsersKeys,
        bmi::indexed_by<
            bmi::ordered_non_unique<bmi::tag<struct TIMESTAMP_tag>,
                                    bmi::member<CrUsersKeys, int, &CrUsersKeys::TIMESTAMP> >,
            bmi::hashed_unique<bmi::tag<struct IMSI_tag>,
                               bmi::member<CrUsersKeys, int, &CrUsersKeys::IMSI> /*, boost::hash<int>, std::equal_to<int>*/>
        >
        /*, bip::allocator<CrUsersKeys,bip::managed_shared_memory::segment_manager>*/
    >
    GlobalHash;

int main() {
    CrMultiIndex<GlobalHash> multi;

    CrUsersKeys key;
    key.IMSI = 2;
    multi.Insert(key);

    int searchKey = 2;
    auto it = multi.GetIteratorBy<IMSI_tag>(searchKey);
    if (it != multi.m_pMultiIndex.get<IMSI_tag>().end())
        std::cout << "found " << std::endl;
}

版画

success
found 

作为对 sehe 回答的补充,这是对 IndexOfTag 的重写,它不依赖于未记录的 Boost.MultiIndex 特性:

Live On Coliru

template<typename MultiIndexContainer,std::size_t N=0>
struct index_position:index_position<MultiIndexContainer,N+1>
{
  using index_type=typename boost::multi_index::nth_index<MultiIndexContainer,N>::type;
  using index_position<MultiIndexContainer,N+1>::case_of;
  static constexpr std::size_t case_of(std::in_place_type_t<index_type>){return N;}
};

template<typename MultiIndexContainer>
struct index_position<
  MultiIndexContainer,
  boost::mpl::size<typename MultiIndexContainer::index_type_list>::value
>
{
  static constexpr void case_of(...){}
};

template <typename MultiIndexContainer,typename Tag>
constexpr std::size_t IndexOfTag()
{
  using index_type=typename boost::multi_index::index<MultiIndexContainer,Tag>::type;
  return index_position<MultiIndexContainer>::case_of(std::in_place_type<index_type>);
}

编辑: 在 C++14 中:

Live On Coliru

template<typename MultiIndexContainer,std::size_t N=0>
struct index_position:index_position<MultiIndexContainer,N+1>
{
  using index_type=typename boost::multi_index::nth_index<MultiIndexContainer,N>::type;
  using index_position<MultiIndexContainer,N+1>::case_of;
  static constexpr std::size_t case_of(index_type*){return N;}
};

template<typename MultiIndexContainer>
struct index_position<
  MultiIndexContainer,
  boost::mpl::size<typename MultiIndexContainer::index_type_list>::value
>
{
  static constexpr void case_of(...){}
};

template <typename MultiIndexContainer,typename Tag>
constexpr std::size_t IndexOfTag()
{
  using index_type=typename boost::multi_index::index<MultiIndexContainer,Tag>::type;
  return index_position<MultiIndexContainer>::case_of((index_type*)(nullptr));
}