两个单独的键映射到std :: map中的单个条目

时间:2016-02-08 15:32:46

标签: c++ stdmap

我正在研究一段代码,其目标是成为一个快速的“搜索引擎”。我在一个文件中有条目,需要在读取整个文件后进行搜索。它们需要可以通过条目的名称进行搜索,并且它从文件的开头偏移。我的问题是内存使用问题,因为有数百万条目。目前我使用两个单独的std :: maps来存储数据,以便可以指定任一搜索项。这导致数据的双重存储,这正是我试图减少的。

我使用valgrind massif发现内存使用的主要部分是条目的双重存储。

目前的储存方法:

struct entry {
    std::string name;
    uint16_t offset;
    uint16_t size;
    bool isConst;
};

nameSearchMap.insert(std::pair<std::string, entry>(s_entry.name, e_entry));
offsetSearchMap.insert(std::pair<uint16_t, SymInfo>(s_entry.offset, s_entry));

有没有办法让我可以制作一个可以通过任何一种键搜索的地图?

4 个答案:

答案 0 :(得分:5)

您可以考虑使用

std::map<std::string, std::shared_ptr<entry>>

用于将字符串映射到条目,以及

std::map<uint16_t, std::shared_ptr<entry>>

请注意,通过使用值有效负载的共享指针(因此对两个映射使用相同的entry对象),可以保存有效负载的大小。虽然您需要支付两个共享指针,但您仍然可以提前确定具体结构。

enter image description here

(感觉就像绘制图表。但重点是内存中只有一个entry对象。)

您可能也对boost::bimap感兴趣。

答案 1 :(得分:2)

  

它们需要通过条目名称和文件开头的偏移量进行搜索。

这向我表明,您可以将数据存储在数组/向量中,并使用映射到数组/向量中的索引的映射。

std::vector<entry> entries;
std::map<std::string, size_t> map1;
std::map<uint16_t, size_t> map2;

答案 2 :(得分:0)

每个条目可以节省三个poiner,并避免条目重复。但是只有在插入不是fetch时才可用的方法:

std:vector<std::string> names;
std:vector<entry> entries;
std:map<uint16_t,size_t> offset2pos;

名称和条目必须以相同的方式排序,所以 名称相等的pos分别具有该名称

names[pos] == entries[pos].name

和map offset2pos可以将偏移量转换为pos

size_t pos = offset2pos[offset]

将名称转换为pos使用二进制搜索(std :: lower_bound)

size_t pos = names.begin() - std::lower_bound( names.begin(), names.end(), offset )

这种技术适用于插入的频率不是fetch的情况。 但算法并非如此微不足道,你需要重新分配offset2pos(可能 每次插入一个或多个元素时重建。

在上面的答案中你需要为每个元素保存:

std :: string,uint16_t,2 * Sptr,4 * Mptr

在我的approuch中:

std :: string,uint16_t,Sptr,2 * Mptr

其中:     Sptr - 是smaprt指针对象的内部指针     Mptr - 映射二进制三节点左右指针

每个条目3个指针就是你的记忆利润。

答案 3 :(得分:0)

您可以按如下方式使用Boost.MultiIndex

<强> Live Coliru Demo

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <cstdint>
#include <string>

struct entry {
  std::string name;
  uint16_t offset;
  uint16_t size;
  bool isConst;
};

using namespace boost::multi_index;

using entry_map=multi_index_container<
  entry,
  indexed_by<
    hashed_unique<tag<struct by_name>,member<entry,std::string,&entry::name>>,
    hashed_unique<tag<struct by_offset>,member<entry,uint16_t,&entry::offset>>
  >
>;

#include <iostream>

int main()
{
  entry_map m={{"hello",0,10,false},{"hi",1,20,true},{"bye",2,15,false}};
  auto&     name_map=m.get<by_name>();
  auto&     offset_map=m.get<by_offset>();

  std::cout<<"size(\"hello\"): "<<name_map.find("hello")->size<<"\n";
  std::cout<<"size(2): "<<offset_map.find(2)->size<<"\n";
}

输出:

size("hello"): 10
size(2): 15