• map 和 set 的一起使用


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

    1. #include
    2. #include
    3. #include
    4. #include
    5. #define IDM_BUNDLE_SET 9 //一个bundle 9 个set
    6. #define BUNDLE_SET_ID 8 //每个 set 8 个id
    7. #define IDM_MALLOC_16 16 //一次 16 个id
    8. #define IDM_MALLOC_32 32
    9. int g_ECMP = 70;
    10. struct bundle_set
    11. {
    12. uint32_t baseId;
    13. uint32_t endId;
    14. bool operator< (const bundle_set &a)const
    15. {
    16. return baseId < a.baseId;
    17. }
    18. };
    19. struct bundle_data
    20. {
    21. uint32_t allocaNum; //一个bundle里已经分配的个数
    22. bundle_set setId[IDM_BUNDLE_SET];
    23. };
    24. class idm_bundle_manager
    25. {
    26. public:
    27. int assign(uint32_t baseId, uint32_t num, uint32_t ldpIdx);
    28. int getLdpById(uint32_t idmId);
    29. int getSetById(uint32_t idmId);
    30. void dumpBundleAll() const;
    31. void dumpBundleByIdx(uint32_t index) const;
    32. void dumpLdpAll()const;
    33. void dumpByLdpIdx(uint32_t ldpIdx)const;
    34. static idm_bundle_manager *instance();
    35. virtual ~idm_bundle_manager();
    36. private:
    37. uint32_t mBundleIdx; //第几个 bundle
    38. uint32_t mSetIdx; //bundle里第几个set, 一共有9个set
    39. uint32_t mIdInBundle; //一个bundle里id数,为 IDM_BUNDLE_SET * BUNDLE_SET_ID
    40. uint32_t mBundleNum; //bundle总个数
    41. std::mutex mtx;
    42. bundle_data *mBundle;
    43. std::map<uint32_t, std::set> mLdpIdmMap;
    44. private:
    45. int32_t findIdleBundle(uint32_t bundleIdx, uint32_t num);
    46. bool insertLdpIdm(uint32_t ldpIdx, uint32_t baseId, uint32_t num);
    47. idm_bundle_manager();
    48. idm_bundle_manager(const idm_bundle_manager&);
    49. idm_bundle_manager& operator=(const idm_bundle_manager&);
    50. };
    51. idm_bundle_manager::idm_bundle_manager():
    52. mBundleIdx(0),
    53. mSetIdx(0),
    54. mIdInBundle(IDM_BUNDLE_SET * BUNDLE_SET_ID),
    55. mBundleNum(0),
    56. mBundle(NULL)
    57. {
    58. mBundleNum = (g_ECMP % IDM_BUNDLE_SET == 0)? g_ECMP / IDM_BUNDLE_SET : (g_ECMP % IDM_BUNDLE_SET + 1);
    59. mBundle = (bundle_data*)malloc(sizeof(bundle_data) * mBundleNum);
    60. memset(mBundle, 0, sizeof(bundle_data) * mBundleNum);
    61. }
    62. idm_bundle_manager::~idm_bundle_manager()
    63. {
    64. if(mBundle)
    65. {
    66. free(mBundle);
    67. mBundle = NULL;
    68. }
    69. }
    70. int32_t idm_bundle_manager::findIdleBundle(uint32_t bundleIdx, uint32_t num)
    71. {
    72. uint32_t i = 0;
    73. for(i = 0; i < mBundleNum; i++) //全部找一遍,因为分配的num不一样导致各个bundle剩余的空间也不一样
    74. {
    75. if(i == bundleIdx) //当前那个不找
    76. {
    77. continue;
    78. }
    79. if(mIdInBundle - mBundle[i].allocaNum >= num)
    80. {
    81. return i;
    82. }
    83. }
    84. return -1;
    85. }
    86. int idm_bundle_manager::assign(uint32_t baseId, uint32_t num, uint32_t ldpIdx)
    87. {
    88. std::lock_guard guard(mtx);
    89. if(mBundleIdx >= mBundleNum) //bundle到最后一个时,重新从0开始
    90. {
    91. mBundleIdx = 0;
    92. }
    93. //当前的 bundle 已经不够容纳 num 个id,找一个空闲的 bundle
    94. if(num > mIdInBundle - mBundle[mBundleIdx].allocaNum)
    95. {
    96. uint32_t idx = findIdleBundle(mBundleIdx, num);
    97. if(-1 == idx)
    98. {
    99. return 0;//找不到能够容纳 num 的 bundle 了
    100. }
    101. mBundleIdx = idx;
    102. }
    103. //算出在bundle里的第几个set(0~8)
    104. mSetIdx = (mBundle[mBundleIdx].allocaNum == 0) ? 0 : mBundle[mBundleIdx].allocaNum / 8;
    105. if(IDM_MALLOC_32 == num)
    106. {
    107. }
    108. else if(IDM_MALLOC_16 == num) //一次16个,跨两个 set
    109. {
    110. mBundle[mBundleIdx].setId[mSetIdx].baseId = baseId;
    111. mBundle[mBundleIdx].setId[mSetIdx].endId = baseId + IDM_MALLOC_16 / 2;
    112. mBundle[mBundleIdx].setId[mSetIdx + 1].baseId = baseId + IDM_MALLOC_16 / 2;
    113. mBundle[mBundleIdx].setId[mSetIdx + 1].endId = baseId + num;
    114. mBundle[mBundleIdx].allocaNum += num;
    115. }
    116. else
    117. {
    118. mBundle[mBundleIdx].setId[mSetIdx].baseId = baseId;
    119. mBundle[mBundleIdx].setId[mSetIdx].endId = baseId + num;
    120. mBundle[mBundleIdx].allocaNum += num;
    121. }
    122. mBundleIdx += 1;
    123. //直接插入map,
    124. if(!insertLdpIdm(ldpIdx, baseId, num))
    125. {
    126. printf("insert ldpIdx(%u) fail\n", ldpIdx);
    127. }
    128. return mSetIdx;
    129. }
    130. int idm_bundle_manager::getLdpById(uint32_t idmId)
    131. {
    132. std::lock_guard guard(mtx);
    133. for(auto ite : mLdpIdmMap)
    134. {
    135. if(idmId >= ite.second.begin()->baseId && idmId <= ite.second.end()->endId)
    136. {
    137. return ite.first;
    138. }
    139. }
    140. return 0;
    141. }
    142. bool idm_bundle_manager::insertLdpIdm(uint32_t ldpIdx, uint32_t baseId, uint32_t num)
    143. {
    144. bundle_set set{baseId, baseId + num -1 };
    145. auto ret = mLdpIdmMap[ldpIdx].insert(set);
    146. return ret.second;
    147. }
    148. int idm_bundle_manager::getSetById(uint32_t idmId)
    149. {
    150. std::lock_guard guard(mtx);
    151. for(uint32_t bundleIdx = 0; bundleIdx < mBundleNum; bundleIdx++)
    152. {
    153. for(uint32_t setId = 0; setId < IDM_BUNDLE_SET; setId++)
    154. {
    155. if(idmId >= mBundle[bundleIdx].setId[setId].baseId && idmId <= mBundle[bundleIdx].setId[setId].endId)
    156. {
    157. return setId;
    158. }
    159. }
    160. }
    161. return -1;
    162. }
    163. void idm_bundle_manager::dumpBundleAll()const
    164. {
    165. for(uint32_t i = 0; i < mBundleNum; i++)
    166. {
    167. printf("bundle_index: %u\n", i);
    168. dumpBundleByIdx(i);
    169. }
    170. }
    171. void idm_bundle_manager::dumpBundleByIdx(uint32_t bundleIdx) const
    172. {
    173. if(bundleIdx >= mBundleNum)
    174. {
    175. return;
    176. }
    177. for(uint32_t i = 0; i < IDM_BUNDLE_SET; i++)
    178. {
    179. printf("\tset_index: %u\n", i);
    180. if(mBundle[bundleIdx].setId[i].baseId)
    181. {
    182. for(uint32_t j = 0; j < BUNDLE_SET_ID; j++)
    183. {
    184. printf("\t %u ", mBundle[bundleIdx].setId[i].baseId + j);
    185. }
    186. }
    187. printf("\n");
    188. }
    189. }
    190. void idm_bundle_manager::dumpByLdpIdx(uint32_t ldpIdx)const
    191. {
    192. if(!mLdpIdmMap.empty())
    193. {
    194. printf("ldpidx = %u\n", ldpIdx);
    195. auto ret = mLdpIdmMap.find(ldpIdx);
    196. if(ret != mLdpIdmMap.end())
    197. {
    198. for(auto ite : ret->second)
    199. {
    200. printf("%u %u\n", ite.baseId, ite.endId);
    201. }
    202. }
    203. }
    204. }
    205. idm_bundle_manager *idm_bundle_manager::instance()
    206. {
    207. static idm_bundle_manager _instance;
    208. return &_instance;
    209. }
    210. #define g_IdmBundleManager (*idm_bundle_manager::instance())
    211. int main()
    212. {
    213. //每次分配8个,最多能分配72次
    214. for(int i = 0; i < 2; i++)
    215. {
    216. int baseId = 1024 + i * 8;
    217. g_IdmBundleManager.assign(baseId, 8, 1073741832);
    218. }
    219. //每次分配16个,最多能分配 bundleNum * 4 次
    220. // for(int i = 0; i < 33; i++)
    221. // {
    222. // int baseId = 10024 + i * 16;
    223. // g_IdmBundleManager.assign(baseId, 16);
    224. // }
    225. g_IdmBundleManager.dumpBundleAll();
    226. g_IdmBundleManager.dumpByLdpIdx(1073741832);
    227. // int idm_id = 10808;
    228. // int setId = g_IdmBundleManager.getSetById(idm_id);
    229. // printf("setId of %d is %d\n", idm_id, setId);
    230. return 0;
    231. }

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

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

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

    1. int idm_bundle_manager::getLdpById(uint32_t idmId)
    2. {
    3. std::lock_guard guard(mtx);
    4. for(auto ite : mLdpIdmMap)
    5. {
    6. if(idmId >= ite.second.begin()->baseId && idmId <= ite.second.end()->endId)
    7. {
    8. return ite.first;
    9. }
    10. }
    11. return 0;
    12. }
    13. bool idm_bundle_manager::insertLdpIdm(uint32_t ldpIdx, uint32_t baseId, uint32_t num)
    14. {
    15. bundle_set set{baseId, baseId + num -1};
    16. auto ret = mLdpIdmMap[ldpIdx].insert(set);
    17. return ret.second;
    18. }

  • 相关阅读:
    Retrofit 使用
    关于不同数据库的SQL中比较串的形式为NULL=NULL的返回值不同
    模仿苹果生态系统,谷歌2022年将致力于跨平台设备整合
    python学习笔记
    【定时器】企业微信群定时发送消息简单实现
    java课程设计:基于SSM实现个人健康管理系统
    Windows搭建uiautomator2和weditor环境
    `算法题解` `LibreOJ` #2491. 「BJOI2018」求和
    数据结构之二叉树(前提知识)
    Gumbel-Softmax完全解析
  • 原文地址:https://blog.csdn.net/tianyexing2008/article/details/133997479