Find boost multi index Tag to index and number of indices

丶灬走出姿态 提交于 2019-12-24 02:28:10

问题


I have a template class(CrMultiIndex) that receive as template parameter a definition of boost multi index(GlobalHash).

I need :

  1. To add statistics to my template class according to Index used. So i need a way to resize the vector(m_StatsByIndex) at init with the number of existing indices.
  2. I still want the user to search according to tag and not index number. So i need a way to convert from tag to index number so i can update statistics in vector according to index in vector.

I have template 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());
}

Here is the definition of boost multi index container:

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

with a search function according to Tag

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

Code is at http://coliru.stacked-crooked.com/a/d97195a6e4bb7ad4


回答1:


As a supplement to sehe's answer, this a rewrite of IndexOfTag that does not depend on undocumented Boost.MultiIndex features:

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

Edit: In 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));
}



回答2:


You'd need to query the embedded index type lists:

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;
}

Or, using Boost Mpl all the way:

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;
}

You can use it like so:

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;
}

DEMO

Note the code has been simplified:

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;
}

Prints

success
found 


来源:https://stackoverflow.com/questions/49232257/find-boost-multi-index-tag-to-index-and-number-of-indices

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!