开源 fifo_map:C++实现的支持插入顺序的高效map (***)

118 篇文章 11 订阅

开源 fifo_map:C++实现的支持插入顺序的高效map  (****)

c++ ini 改造 (  fifo_map) (c++)

C++ 读写配置文件 ini (c++)

FIFO Map in c++


set/multiset 容器

fifo_map 实测注解笔记

------------------------------------------

要点:

1. 作用:按照插入排序。

2. 应用场景:读写 按照插入排序的 map。

比如,json这类文件,

3. 大数据场景,应该不适合吧?

fifo_map 的可靠性:能够出现在 debian官网中,应该还行吧?

///有限个数的 Key: 首先按照用户定制的排列顺序,进行初始化 verMapFiFo。

///这样,以后对 value进行修改,就不会再影响到排列顺序了。

  

    ///保证排列顺序。初始化为“空”字符串,或其他。
    verMapFiFo["Categories"] ="";
    verMapFiFo["Type"] ="";
    verMapFiFo["Name"] ="";

---------------------

1. c++标准库:注重普遍性,重要性。

2. 像 fifo_map这类库,应该不会被纳入标准库吧?

因此,使用第三方的库,还是可以节约许多东西的。

特别是已经被那些主流 linux 发行版收录的。

------------------------------------------

C++ 读写配置文件 ini

  https://wenku.csdn.net/answer/dea0047e89164d6a9bca9023064eb1da

SimpleIni 是一个跨平台的 C++ 库,支持Windows, WinCE and Linux系统,提供一个简单的API用于操作 ini 配置文件


simpleini项目地址:cpp库
https://github.com/brofield/simpleini

下载:debian   https://sources.debian.org/src/libsimpleini/4.20%2Bdfsg-1/

inih : c库

下载:debian   https://sources.debian.org/src/libinih/55-1/

iniparser

下载:debian    https://sources.debian.org/src/iniparser/4.1-6/src/

上述3种,debain官方有在维护,如:

------------------------------------------

github 上不了 xx

使用手册:  https://gitee.com/mirrors_nlohmann/fifo_map

下载:  https://sources.debian.org/src/kicad/6.0.11%2Bdfsg-1/thirdparty/nlohmann_json/nlohmann/fifo_map.hpp/

  https://sources.debian.org/src/kicad/6.0.11%2Bdfsg-1/thirdparty/nlohmann_json/nlohmann/

-

-rw-r--r--13,425fifo_map.hpp

-

-rw-r--r--926,233json.hpp

-

-rw-r--r--2,144json_fwd.hpp

------------------------------------------

思考:插入排序

1. 如何解决 key的唯一性?

2. 大数据的时间效率

3. 删除、插入等操作,还能保证 key的唯一性?

map:正常操作。

vector:专门用于个性化的排序,或查询?

4. 部分的 解决方案

Boost.MultiIndex :这个倒是可以彻底解决问题。但是,小项目使用时,安装,使用都是一件麻烦事。

小项目用这个?https://github.com/nlohmann/fifo_map 删除、插入等功能,应该受限制的吧?

自己编写?小打小闹?

------------------------------------------

C ++ STL map我不希望它排序!>> 插入顺序

https://www.orcode.com/question/515923_k00025.html

1. 没有标准容器可以直接执行您想要的操作。

如果要维护插入顺序,要使用的明显容器是向量。如果您还需要按字符串查找,请使用矢量和地图。地图通常是字符串到矢量索引,但由于您的数据已经是整数,您可能只想复制它,具体取决于您的用例。     

2. Boost.MultiIndex 库似乎是您想要的正确选择。

但是,如果您没有很多C ++经验,这个库在开始时可能会有点难以使用。以下是如何使用库来解决问题代码中的确切问题:

map / set对其项目进行排序

亨尖玛次酥

嗯,没有STL容器实际上做你想要的,但有可能。 1. STL 默认情况下,使用

vector

。这意味着:

struct Entry { std::string name; int it; };

typedef std::vector<Entry> container_type;

如果您希望按字符串搜索,则始终可以使用

find

算法。

class ByName: std::unary_function<Entry,bool>
{
public:
  ByName(const std::string& name): m_name(name) {}
  bool operator()(const Entry& entry) const { return entry.name == m_name; }
private:
  std::string m_name;
};

// Use like this:
container_type myContainer;
container_type::iterator it =
  std::find(myContainer.begin(), myContainer.end(), ByName("A"));

2. Boost.MultiIndex 这似乎有点矫枉过正,但你可以随时在这里查看。 它允许您创建一个存储容器,可通过各种样式的各种索引访问,所有这些都为您(几乎)神奇地维护。 而不是使用一个容器(

std::map

)来引用存储容器(

std::vector

)以及它导致的所有同步问题......你最好使用Boost。

3. fifo_map

梦话快家腹

我偶尔遇到同样的问题,这是我的解决方案:https://github.com/nlohmann/fifo_map。它是一个仅限标头的C ++ 11解决方案,可以作为

std::map

的替代品。 对于您的示例,它可以使用如下:

#include "fifo_map.hpp"
#include <string>
#include <iostream>

using nlohmann::fifo_map;

int main()
{
    fifo_map<std::string,int> persons;

    persons["B"] = 123;
    persons["A"] = 321;

    for(fifo_map<std::string,int>::iterator i = persons.begin();
        i!=persons.end();
        ++i)
    {
        std::cout<< (*i).first << ":"<<(*i).second << std::endl;
    }
}

fifo_map 实测注解笔记:

1. 在 fifo_map.hpp 中,“ fifo_map_compare” 也是一个模板

    template<class Key>
    class fifo_map_compare

表明:fifo_map_compare 是一个模板,不是类。

2. 在 fifo_map.hpp 中,“ fifo_map” 也是一个模板

typename fifo_map::value_type value(std::forward<Args>(args)...);

3. 用法:模板用法,如上。

#include "fifo_map.hpp"

    fifo_map<std::string,int> persons;

    for(fifo_map<std::string,int>::iterator i = persons.begin();

4. 不要使用 persons.insert(),因为当插入多个相同的 key值时,只有第一个语句才有效。

    persons["B"] = 123; //

========================

set/multiset 容器

set容器排序

set容器默认排序规则为从小到大,掌握如何改变排序规则
主要技术点
利用仿函数,可以改变排序规则

  set/multiset 容器_set容器插入重复数字会增加size吗_出类拔萃~的博客-CSDN博客

开源 fifo_map:C++实现的支持插入顺序的高效map  (****)

  C++实现的支持插入顺序的高效map_nlohmann::fifo_map_普通网友的博客-CSDN博客

FIFO Map in c++

  dictionary - FIFO Map in c++ - Stack Overflow

here's no unique solution for this problem, the simplest one would be to use an auxiliary queue for storing the keys in order of insertion.

map<string, string> m_myMap;
queue<string>       m_myQueue;

void insert(const string& key, const string& value) {
  m_myMap.insert(make_pair(key, value));
  m_myQueue.push(key);
}

void deleteOldOnes() {
  while (m_myQueue.size() > MAX_SIZE) {
   m_myMap.erase(m_myQueue.front());
   m_myQueue.pop();
  }
}

You keep using the map for accessing the elements by key, the queue should not be used anywhere else than in the two methods above.

I had the same problem every once in a while and here is my solution: GitHub - nlohmann/fifo_map: a FIFO-ordered associative container for C++. It's a header-only C++11 solution and can be used as drop-in replacement for a std::map.

Example

#include "src/fifo_map.hpp"

// for convenience
using nlohmann::fifo_map;

int main() {
    // create fifo_map with template arguments
    fifo_map<int, std::string> m;

    // add elements
    m[2] = "two";
    m[3] = "three";
    m[1] = "one";

    // output the map; will print
    // 2: two
    // 3: three
    // 1: one
    for (auto x : m) {
        std::cout << x.first << ": " << x.second << "\n";
    }

    // delete an element
    m.erase(2);

    // re-add element
    m[2] = "zwei";

    // output the map; will print
    // 3: three
    // 1: one
    // 2: zwei
    for (auto x : m) {
        std::cout << x.first << ": " << x.second << "\n";
    }
}

Note how the fifo_map's elements are always printed in the order of the insertion. Deletion of old elements is not implemented ( 实现;贯彻;完成), but this extension should not be too difficult.

#include<iostream>
#include<queue>
using namespace std;

main(){

    queue < pair <int,int> > Q; //First use a queue to store the pair wise values
    int a,b;
    // insert value to the queue as a pair
    for (int i=0;i<6;i++){ // i only insert 6 pairs
        cin>>a>>b;
        if (Q.size()>=3){   // if queue size is 3 than pop up the first value
            Q.pop();
        }

        Q.push(make_pair(a,b)); // insert a new pair into the queue
    }

    while(!Q.empty()){  // output the pairs on that queue
        cout<<Q.front().first<<" "<<Q.front().second<<endl;
        Q.pop();
    }

    return 0;

====================

 c++ ini 改造

  https://blog.csdn.net/yangzm/article/details/127106825

      这两天在用ini文件,simpleini排名第一,但有个问题,就是GetKeys枚举出来的结果是排序的,这个很不友好。

     

    /*
       Feather INI Parser - 2.0
       You are free to use this however you wish.
       If you find a bug, please attept to debug the cause.
       Post your environment details and the cause or fix in the issues section of GitHub.
       Written by Turbine1991.
       Website:
       http://code.google.com/p/feather-ini-parser/downloads
       Help:
       Bundled example & readme.
       https://github.com/Turbine1991/cpp-feather-ini-parser/tree/master/example
    */
     
    #pragma once
     
    #include <string>
    #include <fstream>
    #include <sstream>
    #include <algorithm>
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include "fifo_map.hpp"
    #include <vector>
     
    #ifndef FINI_WIDE_SUPPORT
      typedef std::stringstream fini_sstream_t;
      typedef std::string fini_string_t;
      typedef char fini_char_t;
      typedef std::ifstream fini_ifstream_t;
      typedef std::ofstream fini_ofstream_t;
    #else
      typedef std::wstringstream fini_sstream_t;
      typedef std::wstring fini_string_t;
      typedef wchar_t fini_char_t;
      typedef std::wifstream fini_ifstream_t;
      typedef std::wofstream fini_ofstream_t;
    #endif
     
     
    fini_string_t& l_trim(fini_string_t& str, const fini_string_t trim_chars = "\t\v\f; ") {
      str.erase(0, str.find_first_not_of(trim_chars)); return str;
    }
     
    fini_string_t& r_trim(fini_string_t& str, const fini_string_t trim_chars = "\t\v\f; ") {
      str.erase(str.find_last_not_of(trim_chars) + 1); return str;
    }
     
    fini_string_t& trim(fini_string_t& str, const fini_string_t trim_chars = "\t\v\f; ") {
      return l_trim(r_trim(str, trim_chars), trim_chars);
    }
     
    template <typename T>
    T convert_to (const fini_string_t &str) {
      fini_sstream_t ss(str);
      T num;
      ss >> num;
      return num;
    }
     
    template <>
    fini_string_t convert_to<fini_string_t>(const fini_string_t &str) {
      return str;
    }
     
    template <>
    const char* convert_to<const char*>(const fini_string_t &str) {
      return str.c_str();
    }
     
    ///
    class INI
    {
    public:
    /// Define
      static int PARSE_FLAGS, SAVE_FLAGS;
     
      typedef fini_char_t data_t;
     
      typedef typename nlohmann::fifo_map<fini_string_t, fini_string_t> keys_t;
      typedef typename nlohmann::fifo_map<fini_string_t, keys_t*> sections_t;
      typedef typename keys_t::value_type keyspair_t;
      typedef typename sections_t::value_type sectionspair_t;
     
      enum source_e {SOURCE_FILE, SOURCE_MEMORY};
      enum save_e {SAVE_PRUNE = 1 << 0, SAVE_PADDING_SECTIONS = 1 << 1, SAVE_SPACE_SECTIONS = 1 << 2, SAVE_SPACE_KEYS  = 1 << 3, SAVE_TAB_KEYS  = 1 << 4, SAVE_SEMICOLON_KEYS  = 1 << 5};
      enum parse_e {PARSE_COMMENTS_SLASH = 1 << 0, PARSE_COMMENTS_HASH = 1 << 1, PARSE_COMMENTS_ALL = 1 << 2};
     
    /// Data
       const source_e source;
       const fini_string_t filename;
       //data_t* data;
       //size_t dataSize;
     
       keys_t* current;
       sections_t sections;
     
    /// Methods
      INI(const INI& from);
      INI(fini_string_t filename, bool doParse, int parseFlags = 0);
      //INI(void* data, size_t dataSize, bool doParse)
      ~INI();
      void clear();
      bool parse(int parseFlags = 0);
      void _parseFile(fini_ifstream_t& file, int parseFlags);
      bool save(fini_string_t filename, int saveFlags = 0);
     
      keys_t& operator[](fini_string_t section);
      void create(fini_string_t section);
      void remove(fini_string_t section);
      bool select(fini_string_t section, bool noCreate = false);
      fini_string_t get(fini_string_t section, fini_string_t key, fini_string_t def);
      fini_string_t get(fini_string_t key, fini_string_t def);
        template<class T>
      T getAs(fini_string_t section, fini_string_t key, T def = T());
        template<class T>
      T getAs(fini_string_t key, T def = T());
      void set(fini_string_t section, fini_string_t key, fini_string_t value);
      void set(fini_string_t key, fini_string_t value);
    };
     
    /// Definition
    INI::INI(const INI& from): source(from.source), filename(from.filename) {
      // Deep clone INI
      for(auto i: from.sections) {
        select(i.first);
        for(auto j: *i.second)
          set(j.first, j.second);
      }
    }
     
    INI::INI(fini_string_t filename, bool doParse, int parseFlags): source(SOURCE_FILE), filename(filename) {
      this->create("");
     
      if (doParse)
         parse(parseFlags);
    }
     
    INI:: ~INI() {
      clear();
    }
     
    void INI::clear() {
      sections.clear();
    }
     
    bool INI::parse(int parseFlags) {
      parseFlags = (parseFlags > 0)? parseFlags: PARSE_FLAGS;
     
      switch(source)
      {
        case SOURCE_FILE: {
          fini_ifstream_t file(filename);
     
          if (!file.is_open())
            return false;
     
          _parseFile(file, parseFlags);
     
          file.close();
          } break;
     
        case SOURCE_MEMORY:
          /*std::stringstream sstream;
          sstream.rdbuf()->pubsetbuf(data, dataSize);
          parse(sstream);*/
          break;
      }
     
      return true;
    }
     
    int INI::PARSE_FLAGS = 0, INI::SAVE_FLAGS = 0;
     
    void INI::_parseFile(fini_ifstream_t& file, int parseFlags) {
      fini_string_t line;
      fini_string_t section; // Set default section (support for sectionless files)
      size_t i = 0;
      keys_t* current = this->current;
     
      while(std::getline(file, line)) {
        i++;
     
        // Parse comments
        if (parseFlags & PARSE_COMMENTS_SLASH || parseFlags & PARSE_COMMENTS_ALL)
          line = line.substr(0, line.find("//"));
        if (parseFlags & PARSE_COMMENTS_HASH || parseFlags & PARSE_COMMENTS_ALL)
          line = line.substr(0, line.find("#"));
     
        if (trim(line).size() == 0) // Skip empty lines
          continue;
     
        if ('[' == line.at(0)) { // Section
          section = trim(line, "[] "); // Obtain key value, including contained spaced
          if (section.size() == 0) // If no section value, use default section
            current = this->current;
     
          if (sections.find(section) != sections.end()) {
            std::cerr << "Error: cpp-feather-ini-parser: Duplicate section '" + section + "':" << i << std::endl;
            throw -1;
          }
     
          current = new keys_t;
          sections[section] = current;
        } else {
          size_t indexEquals = line.find("=");
          if (indexEquals != fini_string_t::npos) {
            fini_string_t key = line.substr(0, indexEquals), value = line.substr(indexEquals + 1);
            r_trim(key);
            l_trim(value);
     
            if ((*current).find(key) != (*current).end()) {
              std::cerr << "Error: cpp-feather-ini-parser: Duplicate key '" + key + "':" << i << std::endl;
              throw -1;
            }
     
            (*current).emplace(key, value);
          }
        }
      }
    }
     
    bool INI::save(fini_string_t filename, int saveFlags) {
      saveFlags = (saveFlags > 0)? saveFlags: SAVE_FLAGS;
     
      fini_ofstream_t file((filename == "")? this->filename: filename, std::ios::trunc);
      if (!file.is_open())
         return false;
     
      // Save remaining sections
      for(auto i: sections) {
        //if (i.first == "")
        //  continue;
        if (saveFlags & SAVE_PRUNE && i.second->size() == 0)  // No keys/values in section, skip to next
          continue;
     
        // Write section
        if (i.first != "") {
          if (saveFlags & SAVE_SPACE_SECTIONS)
            file << "[ " << i.first << " ]" << std::endl;
          else
            file << '[' << i.first << ']' << std::endl;
        }
     
        // Loop through key & values
        for(auto j: *i.second) {
          if (saveFlags & SAVE_PRUNE && j.second == "")
            continue;
     
          // Write key & value
          if (saveFlags & SAVE_TAB_KEYS && i.first != "")
            file << '\t'; // Insert indent
     
          if (saveFlags & SAVE_SPACE_KEYS)
            file << j.first << " = " << j.second;
          else
            file << j.first << '=' << j.second;
     
          if (saveFlags & SAVE_SEMICOLON_KEYS)
            file << ';';
     
          file << std::endl;
        }
     
        // New section line
        if (saveFlags & SAVE_PADDING_SECTIONS)
          file << '\n';
      }
     
      file.close();
     
      return true;
    }
     
    //Provide bracket access to section contents
    INI::keys_t& INI::operator[](fini_string_t section) {
      select(section);
      return *current;
    }
     
    //Create a new section and select it
    void INI::create(fini_string_t section) {
      if (section != "" && sections.find(section) != sections.end()) {
        std::cerr << "Error: cpp-feather-ini-parser: Duplicate section '" << section << "'" << std::endl;
        throw -1;
      }
     
      current = new keys_t;
      sections[section] = current;
    }
     
    //Removes a section including all key/value pairs
    void INI::remove(fini_string_t section) {
      if (select(section, true))
        sections.erase(section);
     
      current = NULL;
    }
     
    //Select a section for performing operations
    bool INI::select(fini_string_t section, bool noCreate) {
      sections_t::iterator sectionsit = sections.find(section);
      if (sectionsit == sections.end()) {
         if (!noCreate)
           create(section);
     
         return false;
      }
     
      current = sectionsit->second;
      return true;
    }
     
    fini_string_t INI::get(fini_string_t section, fini_string_t key, fini_string_t def) {
      return get(key, def);
    }
     
    fini_string_t INI::get(fini_string_t key, fini_string_t def) {
      auto it = current->find(key);
      if (it == current->end())
         return def;
     
      return it->second;
    }
     
      template<class T>
    T INI::getAs(fini_string_t section, fini_string_t key, T def) {
      return getAs<T>(key, def);
    }
     
      template<class T>
    T INI::getAs(fini_string_t key, T def) {
      auto it = current->find(key);
      if (it == current->end())
         return def;
     
      return convert_to<T>(it->second);
    }
     
    void INI::set(fini_string_t section, fini_string_t key, fini_string_t value) {
      if (!select(section))
        create(section);
     
      set(key, value);
    }
     
    void INI::set(fini_string_t key, fini_string_t value) {
      (*current)[key] = value;
    }

修改有三处:

    #include "fifo_map.hpp"

      typedef typename nlohmann::fifo_map<fini_string_t, fini_string_t> keys_t; //84行
      typedef typename nlohmann::fifo_map<fini_string_t, keys_t*> sections_t; // 85行
     

fifo_map.hpp是不排序c++ map结构。

修改后的测试代码:

    #include <Windows.h>
    #include <filesystem>
    #include <iostream>
    #include <fstream>
    #include "INI.h"
     
    using namespace std;
     
    #include <atlbase.h>
    #include <atlconv.h>
     
    int main()
    {
        INI ini2("file.ini", true);
     
        ini2.select("Section3", true);
        std::wstring vv  = CA2W(ini2.get("b", "").c_str(), CP_UTF8);
        std::wstring vv2 = CA2W(ini2.get("a", "").c_str(), CP_UTF8);
     
        auto it = ini2.sections["Section3"];
        for (auto jj : *it) {
            int c = 0;
        }
     
        for (auto i : ini2.sections) {
            cout << "[" << i.first << "]" << endl;
     
            for (auto j : *i.second) {
                std::string key = j.first;
                std::wstring wValue = CA2W(j.second.c_str(), CP_UTF8);
     
                cout << "  " << j.first << "=" << j.second << endl;
            }
        }
     
        int c = 0;
    }

    file.ini

    [Section3]
    b = 你好
    a = 测试

好了,现在运行后,就不会有 排序的问题了。
————————————————
版权声明:本文为CSDN博主「杨宗卫的爸爸」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yangzm/article/details/127106825

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值