map 和 set 的一起使用

news2024/11/18 10:29:23

        map 和 set 一起使用的场景其实也蛮多的,最近业务上就遇到了。需求是这样的,一条路径(mpls中的lsp)会申请多个 id,这个 id 是独一无二的。这里很显然就就一个”一对多“的情况,合适用这个容器不保存这些信息,如:std::map<uint32_t, std::set<bundle_set>> mLdpIdmMap; 下面为一个完成的可编译运行的代码,只是功能并不完善。

#include <mutex>
#include <map>
#include <set>
#include <string.h>

#define IDM_BUNDLE_SET 9  //一个bundle 9 个set
#define BUNDLE_SET_ID 8   //每个 set 8 个id
#define IDM_MALLOC_16 16 //一次 16 个id
#define IDM_MALLOC_32 32

int g_ECMP = 70;

struct bundle_set
{
    uint32_t baseId;
    uint32_t endId;
    bool operator< (const bundle_set &a)const
    {
        return baseId < a.baseId;
    }
};
struct bundle_data
{
    uint32_t allocaNum;  //一个bundle里已经分配的个数  
    bundle_set setId[IDM_BUNDLE_SET];
};

class idm_bundle_manager
{
public:
    int assign(uint32_t baseId, uint32_t num, uint32_t ldpIdx);
    int getLdpById(uint32_t idmId);
    int getSetById(uint32_t idmId);
    void dumpBundleAll() const;
    void dumpBundleByIdx(uint32_t index) const;
    void dumpLdpAll()const;
    void dumpByLdpIdx(uint32_t ldpIdx)const;
    static idm_bundle_manager *instance();

    virtual ~idm_bundle_manager();
private:
    uint32_t    mBundleIdx; //第几个 bundle
    uint32_t    mSetIdx; //bundle里第几个set, 一共有9个set
    uint32_t    mIdInBundle; //一个bundle里id数,为 IDM_BUNDLE_SET * BUNDLE_SET_ID
    uint32_t    mBundleNum; //bundle总个数
    std::mutex  mtx;
    bundle_data *mBundle;
    std::map<uint32_t, std::set<bundle_set>> mLdpIdmMap;
    
private:
    int32_t findIdleBundle(uint32_t bundleIdx, uint32_t num);
    bool insertLdpIdm(uint32_t ldpIdx, uint32_t baseId, uint32_t num);
    idm_bundle_manager();
    
    idm_bundle_manager(const idm_bundle_manager&);
    idm_bundle_manager& operator=(const idm_bundle_manager&);
};

idm_bundle_manager::idm_bundle_manager(): 
mBundleIdx(0),
mSetIdx(0),
mIdInBundle(IDM_BUNDLE_SET * BUNDLE_SET_ID),
mBundleNum(0),
mBundle(NULL)
{
    mBundleNum = (g_ECMP % IDM_BUNDLE_SET == 0)? g_ECMP / IDM_BUNDLE_SET : (g_ECMP % IDM_BUNDLE_SET + 1);
    mBundle = (bundle_data*)malloc(sizeof(bundle_data) * mBundleNum);
    memset(mBundle, 0, sizeof(bundle_data) * mBundleNum);
}

idm_bundle_manager::~idm_bundle_manager()
{
    if(mBundle)
    {
        free(mBundle);
        mBundle = NULL;
    }
}

int32_t idm_bundle_manager::findIdleBundle(uint32_t bundleIdx, uint32_t num)
{
    uint32_t i = 0;
    for(i = 0; i < mBundleNum; i++)  //全部找一遍,因为分配的num不一样导致各个bundle剩余的空间也不一样
    {
        if(i == bundleIdx) //当前那个不找
        {
            continue;
        }

        if(mIdInBundle - mBundle[i].allocaNum >= num)
        {
            return i;
        }
    }
    return -1;
}

int idm_bundle_manager::assign(uint32_t baseId, uint32_t num, uint32_t ldpIdx)
{
    std::lock_guard<std::mutex> guard(mtx);
    if(mBundleIdx >= mBundleNum) //bundle到最后一个时,重新从0开始
    {
        mBundleIdx = 0;
    }

    //当前的 bundle 已经不够容纳 num 个id,找一个空闲的 bundle
    if(num > mIdInBundle - mBundle[mBundleIdx].allocaNum)
    {
        uint32_t idx = findIdleBundle(mBundleIdx, num);
        if(-1 == idx)
        {
            return 0;//找不到能够容纳 num 的 bundle 了
        }
        mBundleIdx = idx;
    }

    //算出在bundle里的第几个set(0~8)
    mSetIdx = (mBundle[mBundleIdx].allocaNum == 0) ? 0 : mBundle[mBundleIdx].allocaNum / 8;
    
    if(IDM_MALLOC_32 == num)
    {

    }
    else if(IDM_MALLOC_16 == num) //一次16个,跨两个 set
    {
        mBundle[mBundleIdx].setId[mSetIdx].baseId = baseId;
        mBundle[mBundleIdx].setId[mSetIdx].endId = baseId + IDM_MALLOC_16 / 2;

        mBundle[mBundleIdx].setId[mSetIdx + 1].baseId = baseId + IDM_MALLOC_16 / 2;
        mBundle[mBundleIdx].setId[mSetIdx + 1].endId = baseId + num;
        mBundle[mBundleIdx].allocaNum += num;
    }
    else
    {
        mBundle[mBundleIdx].setId[mSetIdx].baseId = baseId;
        mBundle[mBundleIdx].setId[mSetIdx].endId = baseId + num;
        mBundle[mBundleIdx].allocaNum += num;        
    }

    mBundleIdx += 1;

    //直接插入map,
    if(!insertLdpIdm(ldpIdx, baseId, num))
    {
        printf("insert ldpIdx(%u) fail\n", ldpIdx);
    }

    return mSetIdx;
}

int idm_bundle_manager::getLdpById(uint32_t idmId)
{
    std::lock_guard<std::mutex> guard(mtx);
    for(auto ite : mLdpIdmMap)
    {
        if(idmId >= ite.second.begin()->baseId && idmId <= ite.second.end()->endId)
        {
            return ite.first;
        }
    }

    return 0;
}

bool idm_bundle_manager::insertLdpIdm(uint32_t ldpIdx, uint32_t baseId, uint32_t num)
{
    bundle_set set{baseId, baseId + num -1 };
    auto ret = mLdpIdmMap[ldpIdx].insert(set);
    return ret.second;
}

int idm_bundle_manager::getSetById(uint32_t idmId)
{
    std::lock_guard<std::mutex> guard(mtx);
    for(uint32_t bundleIdx = 0; bundleIdx < mBundleNum; bundleIdx++)
    {
        for(uint32_t setId = 0; setId < IDM_BUNDLE_SET; setId++)
        {
            if(idmId >= mBundle[bundleIdx].setId[setId].baseId && idmId <= mBundle[bundleIdx].setId[setId].endId)
            {
                return setId;
            }
        } 
    }
    return -1;
}

void idm_bundle_manager::dumpBundleAll()const
{
    for(uint32_t i = 0; i < mBundleNum; i++)
    {
        printf("bundle_index: %u\n", i);
        dumpBundleByIdx(i);
    }
}

void idm_bundle_manager::dumpBundleByIdx(uint32_t bundleIdx) const
{
    if(bundleIdx >= mBundleNum)
    {
        return;
    }

    for(uint32_t i = 0; i < IDM_BUNDLE_SET; i++)
    {
        printf("\tset_index: %u\n", i);
        if(mBundle[bundleIdx].setId[i].baseId)
        {
            for(uint32_t j = 0; j < BUNDLE_SET_ID; j++)
            {  
                printf("\t %u ", mBundle[bundleIdx].setId[i].baseId + j);
            }
        }

        printf("\n");
    }
}

void idm_bundle_manager::dumpByLdpIdx(uint32_t ldpIdx)const
{
    if(!mLdpIdmMap.empty())
    {
        printf("ldpidx = %u\n", ldpIdx);
        auto ret = mLdpIdmMap.find(ldpIdx);
        if(ret != mLdpIdmMap.end())
        {
            for(auto ite : ret->second)
            {
                printf("%u %u\n", ite.baseId, ite.endId);
            }
        }
    }
}

idm_bundle_manager *idm_bundle_manager::instance()
{
    static idm_bundle_manager _instance;
    return &_instance;
}

#define g_IdmBundleManager (*idm_bundle_manager::instance())

int main()
{
    //每次分配8个,最多能分配72次
    for(int i = 0; i < 2; i++)
    {
        int baseId = 1024 + i * 8;
        g_IdmBundleManager.assign(baseId, 8, 1073741832);
    }

    //每次分配16个,最多能分配 bundleNum * 4 次
    // for(int i = 0; i < 33; i++)
    // {
    //     int baseId = 10024 + i * 16;
    //     g_IdmBundleManager.assign(baseId, 16);
    // }

    g_IdmBundleManager.dumpBundleAll();
    g_IdmBundleManager.dumpByLdpIdx(1073741832);
    // int idm_id = 10808;
    // int setId = g_IdmBundleManager.getSetById(idm_id);
    // printf("setId of %d is %d\n", idm_id, setId);

    return 0;
}

这里主要借这个说明一下 set,set 里的元素是唯一的,且是有序的,它和 map 的底层实现同样的红黑树,所以如果 set 的元素类型是自定义类型的,则必须要实现 operator< 否则是无法编译的。如:

因为  set 的元素是有序的,所以每次插入元素都要进行比较。那实现 operator> 是否可行 ,反正都是比较,其实是不行的,因为它底层实现就是用的 小于号 < ,如错误所示。

使用 auto 进行插入及读取数据的代码:

int idm_bundle_manager::getLdpById(uint32_t idmId)
{
    std::lock_guard<std::mutex> guard(mtx);
    for(auto ite : mLdpIdmMap)
    {
        if(idmId >= ite.second.begin()->baseId && idmId <= ite.second.end()->endId)
        {
            return ite.first;
        }
    }

    return 0;
}

bool idm_bundle_manager::insertLdpIdm(uint32_t ldpIdx, uint32_t baseId, uint32_t num)
{
    bundle_set set{baseId, baseId + num -1};
    auto ret = mLdpIdmMap[ldpIdx].insert(set);
    return ret.second;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1124936.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java集合类面试九】、介绍一下HashMap的扩容机制

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;介绍一下HashMap的扩容机…

【Java集合类面试七】、 JDK7和JDK8中的HashMap有什么区别?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;JDK7和JDK8中的HashMap有…

【保姆级教程】:docker搭建MongoDB三节点副本集

容器可以理解为一个进程&#xff0c;镜像是把环境&#xff0c;组件等都配置好&#xff0c;运行成容器的&#xff0c;容器里面运行服务&#xff0c;也可以说是一个进程。镜像是模板&#xff0c;镜像是实例。 一个镜像可以创建多个实例。也就是多个容器&#xff0c;容器之间相互…

【已解决】vue项目之爆红红红红······

我是用npm update更新依赖的时候就开始爆红了... 这里显示是依赖问题&#xff0c;有多种解决方式&#xff1a;1&#xff0c;哪个依赖出问题就去提高或者降低依赖的版本&#xff1b;2&#xff0c;提高或者降低vue-cli的版本。 第一种&#xff1a; 我的报错信息提示eslint这个依…

Linux系统开发(1):IO多路复用

IO即输入输出&#xff0c;是主存和外部设备&#xff08;磁盘驱动器、终端和网络&#xff09;之间复制数据的过程。 IO过程 应用程序进程向操作系统发起IO调用请求&#xff1b;操作系统将外部设备的数据加载到内核缓冲区&#xff1b;操作系统将内核缓冲区的数据拷贝到进程缓冲…

Linux:firewalld防火墙-小环境实验(3)

环境介绍 本章为全纯手打&#xff0c;无任何复制&#xff0c;如果哪句命令出错&#xff0c;请评论出来我会快速修改 需求 图中防火墙区域为网关服务器上分区 &#xff0c;在网站服务器上可以使用默认的或者别的 1&#xff09;首先关闭全部的服务器的防火墙&#xff0c;实现全…

【GWO-BP预测】基于灰狼算法优化BP神经网络回归预测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

YOLOv5项目实战(1)— 如何去训练模型

前言:Hello大家好,我是小哥谈。YOLOv5基础知识入门系列、YOLOv5源码中的参数超详细解析系列、YOLOv5入门实践系列、YOLOv5论文作图教程系列和YOLOv5算法改进系列学习完成之后,接着就进入YOLOv5项目实战系列了。🎉为了让大家能够牢固地掌握YOLOv5算法,本系列文章就通过一个…

高级二-十进制转换算法

输入二进制数字符串&#xff0c;按二进制数位权重计算&#xff0c;输出十进制数。 (本笔记适合熟悉二进制数和字符串的 coder 翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程…

Excel多线程导入数据库

文章目录 Excel多线程导入数据库1. CountDownLatch2.多线程导入数据库 Excel多线程导入数据库 书接上文 Excel20w数据5s导入 1. CountDownLatch CountDownLatch 维护了一个计数器&#xff0c;初始值为指定的数量。当一个或多个线程调用 await() 方法时&#xff0c;它们会被阻…

Dapper中使用字符串作为动态参数查询时,结果不是预期的问题

1、如下图&#xff0c;c.industryId作为string类型当作参数传递&#xff0c;解析时会加单引号&#xff0c;即&#xff1a;”c.industryId“&#xff0c; 生成的查询语句就会变成 -- 这里把c.IndustryGroup 当成实际的值所以会查询不出数据 select b.Name,COUNT(c.Id) Num …

驱动作业10.23

现象 test.c #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include "head.h"in…

潮玩宇宙源码开发:开启全新的数字潮流时代

随着数字技术的飞速发展和人们对于娱乐需求的不断提升&#xff0c;潮玩宇宙源码开发逐渐成为了新的热门话题。潮玩宇宙是一个集潮流、艺术、科技于一体的数字娱乐新领域&#xff0c;通过将虚拟现实、增强现实等技术融入传统玩具设计中&#xff0c;为玩家们带来了全新的互动体验…

从零开始 Spring Cloud 15:多级缓存

从零开始 Spring Cloud 15&#xff1a;多级缓存 多级缓存架构 传统的缓存使用 Redis&#xff0c;大致架构如下&#xff1a; 这个架构存在一些问题&#xff1a; 请求要经过Tomcat处理&#xff0c;Tomcat的性能成为整个系统的瓶颈 Redis缓存失效时&#xff0c;会对数据库产生冲…

可在耳塞上记录大脑活动的3D打印传感器,未来或可用于诊断神经性疾病

原创 | 文 BFT机器人 加州大学圣地亚哥分校的研究人员探寻到一种方法&#xff0c;可以将日常耳塞变成可以记录大脑内部电活动的高科技设备。通过3D丝网打印的柔性传感器不仅能够检测来自大脑的电生理活动&#xff0c;还能收集人体的汗液乳酸——它是身体在运动和正常代谢活动过…

Risc0:使用Continunations来证明任意EVM交易

1. 引言 RISC Zero&#xff0c;设想了一个基于零知识证明的无限计算的未来。 2023年5月发布了RISC Zero zkVM v0.15版本&#xff0c;其中包含了一种重要feature&#xff1a; continuations。 在RISC Zero zkVM中&#xff0c;continuations为一种机制&#xff1a; 用于将大…

Apollo与TypeScript:强大类型检查在前端开发中的应用

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

如何制作.exe免安装绿色单文件程序,将源代码打包成可独立运行的exe文件

环境: rustdesk编译文件和文件夹 文件程序制作工具 问题描述: 如何制作.exe免安装绿色单文件程序,将源代码打包成可独立运行的exe文件,像官网那种呢? 将下面编译好的rustdesk文件夹制作成一个.exe免安装绿色单文件程序,点击exe就可以运行 在github上找了半天也没有…

大模型的实践应用3-大模型的基础架构Transformer模型,掌握Transformer就掌握了大模型的灵魂骨架

大家好,我是微学AI,今天给大家介绍一下大模型的实践应用3-大模型的基础架构Transformer模型,掌握Transformer就掌握了大模型的灵魂骨架。Transformer是一种基于自注意力机制的深度学习模型,由Vaswani等人在2017年的论文《Attention is All You Need》中提出。它最初被设计用…

【Java集合类面试十一】、HashMap为什么用红黑树而不用B树?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;HashMap为什么用红黑树而…