LocUnorderedSetMap.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /* Copyright (c) 2015, 2017, 2020 The Linux Foundation. All rights reserved.
  2. *
  3. * Redistribution and use in source and binary forms, with or without
  4. * modification, are permitted provided that the following conditions are
  5. * met:
  6. * * Redistributions of source code must retain the above copyright
  7. * notice, this list of conditions and the following disclaimer.
  8. * * Redistributions in binary form must reproduce the above
  9. * copyright notice, this list of conditions and the following
  10. * disclaimer in the documentation and/or other materials provided
  11. * with the distribution.
  12. * * Neither the name of The Linux Foundation, nor the names of its
  13. * contributors may be used to endorse or promote products derived
  14. * from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
  17. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  18. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
  19. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
  20. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  21. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  22. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  23. * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  24. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  25. * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  26. * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. *
  28. */
  29. #ifndef __LOC_UNORDERDED_SETMAP_H__
  30. #define __LOC_UNORDERDED_SETMAP_H__
  31. #include <algorithm>
  32. #include <loc_pla.h>
  33. #ifdef NO_UNORDERED_SET_OR_MAP
  34. #include <set>
  35. #include <map>
  36. #define unordered_set set
  37. #define unordered_map map
  38. #else
  39. #include <unordered_set>
  40. #include <unordered_map>
  41. #endif
  42. using std::unordered_set;
  43. using std::unordered_map;
  44. namespace loc_util {
  45. // Trim from *fromSet* any elements that also exist in *rVals*.
  46. // The optional *goneVals*, if not null, will be populated with removed elements.
  47. template <typename T>
  48. inline static void trimSet(unordered_set<T>& fromSet, const unordered_set<T>& rVals,
  49. unordered_set<T>* goneVals) {
  50. for (auto val : rVals) {
  51. if (fromSet.erase(val) > 0 && nullptr != goneVals) {
  52. goneVals->insert(val);
  53. }
  54. }
  55. }
  56. // this method is destructive to the input unordered_sets.
  57. // the return set is the interset extracted out from the two input sets, *s1* and *s2*.
  58. // *s1* and *s2* will be left with the intersect removed from them.
  59. template <typename T>
  60. static unordered_set<T> removeAndReturnInterset(unordered_set<T>& s1, unordered_set<T>& s2) {
  61. unordered_set<T> common = {};
  62. for (auto b = s2.begin(); b != s2.end(); b++) {
  63. auto a = find(s1.begin(), s1.end(), *b);
  64. if (a != s1.end()) {
  65. // this is a common item of both l1 and l2, remove from both
  66. // but after we add to common
  67. common.insert(*a);
  68. s1.erase(a);
  69. s2.erase(b);
  70. }
  71. }
  72. return common;
  73. }
  74. template <typename KEY, typename VAL>
  75. class LocUnorderedSetMap {
  76. unordered_map<KEY, unordered_set<VAL>> mMap;
  77. // Trim the VALs pointed to by *iter*, with everything that also exist in *rVals*.
  78. // If the set becomes empty, remove the map entry. *goneVals*, if not null, records
  79. // the trimmed VALs.
  80. bool trimOrRemove(typename unordered_map<KEY, unordered_set<VAL>>::iterator iter,
  81. const unordered_set<VAL>& rVals, unordered_set<VAL>* goneVals) {
  82. trimSet<VAL>(iter->second, rVals, goneVals);
  83. bool removeEntry = (iter->second.empty());
  84. if (removeEntry) {
  85. mMap.erase(iter);
  86. }
  87. return removeEntry;
  88. }
  89. public:
  90. inline LocUnorderedSetMap() {}
  91. inline LocUnorderedSetMap(size_t size) : LocUnorderedSetMap() {
  92. mMap.get_allocator().allocate(size);
  93. }
  94. inline bool empty() { return mMap.empty(); }
  95. // This gets the raw pointer to the VALs pointed to by *key*
  96. // If the entry is not in the map, nullptr will be returned.
  97. inline unordered_set<VAL>* getValSetPtr(const KEY& key) {
  98. auto entry = mMap.find(key);
  99. return (entry != mMap.end()) ? &(entry->second) : nullptr;
  100. }
  101. // This gets a copy of VALs pointed to by *key*
  102. // If the entry is not in the map, an empty set will be returned.
  103. inline unordered_set<VAL> getValSet(const KEY& key) {
  104. auto entry = mMap.find(key);
  105. return (entry != mMap.end()) ? entry->second : unordered_set<VAL>{};
  106. }
  107. // This gets all the KEYs from the map
  108. inline unordered_set<KEY> getKeys() {
  109. unordered_set<KEY> keys = {};
  110. for (auto entry : mMap) {
  111. keys.insert(entry.first);
  112. }
  113. return keys;
  114. }
  115. inline bool remove(const KEY& key) {
  116. return mMap.erase(key) > 0;
  117. }
  118. // This looks into all the entries keyed by *keys*. Remove any VALs from the entries
  119. // that also exist in *rVals*. If the entry is left with an empty set, the entry will
  120. // be removed. The optional parameters *goneKeys* and *goneVals* will record the KEYs
  121. // (or entries) and the collapsed VALs removed from the map, respectively.
  122. inline void trimOrRemove(unordered_set<KEY>&& keys, const unordered_set<VAL>& rVals,
  123. unordered_set<KEY>* goneKeys, unordered_set<VAL>* goneVals) {
  124. trimOrRemove(keys, rVals, goneKeys, goneVals);
  125. }
  126. inline void trimOrRemove(unordered_set<KEY>& keys, const unordered_set<VAL>& rVals,
  127. unordered_set<KEY>* goneKeys, unordered_set<VAL>* goneVals) {
  128. for (auto key : keys) {
  129. auto iter = mMap.find(key);
  130. if (iter != mMap.end() && trimOrRemove(iter, rVals, goneVals) && nullptr != goneKeys) {
  131. goneKeys->insert(iter->first);
  132. }
  133. }
  134. }
  135. // This adds all VALs from *newVals* to the map entry keyed by *key*. Or if it
  136. // doesn't exist yet, add the set to the map.
  137. bool add(const KEY& key, const unordered_set<VAL>& newVals) {
  138. bool newEntryAdded = false;
  139. if (!newVals.empty()) {
  140. auto iter = mMap.find(key);
  141. if (iter != mMap.end()) {
  142. iter->second.insert(newVals.begin(), newVals.end());
  143. } else {
  144. mMap[key] = newVals;
  145. newEntryAdded = true;
  146. }
  147. }
  148. return newEntryAdded;
  149. }
  150. // This adds to each of entries in the map keyed by *keys* with the VALs in the
  151. // *enwVals*. If there new entries added (new key in *keys*), *newKeys*, if not
  152. // null, would be populated with those keys.
  153. inline void add(const unordered_set<KEY>& keys, const unordered_set<VAL>&& newVals,
  154. unordered_set<KEY>* newKeys) {
  155. add(keys, newVals, newKeys);
  156. }
  157. inline void add(const unordered_set<KEY>& keys, const unordered_set<VAL>& newVals,
  158. unordered_set<KEY>* newKeys) {
  159. for (auto key : keys) {
  160. if (add(key, newVals) && nullptr != newKeys) {
  161. newKeys->insert(key);
  162. }
  163. }
  164. }
  165. // This puts *newVals* into the map keyed by *key*, and returns the VALs that are
  166. // in effect removed from the keyed VAL set in the map entry.
  167. // This call would also remove those same VALs from *newVals*.
  168. inline unordered_set<VAL> update(const KEY& key, unordered_set<VAL>& newVals) {
  169. unordered_set<VAL> goneVals = {};
  170. if (newVals.empty()) {
  171. mMap.erase(key);
  172. } else {
  173. auto curVals = mMap[key];
  174. mMap[key] = newVals;
  175. goneVals = removeAndReturnInterset(curVals, newVals);
  176. }
  177. return goneVals;
  178. }
  179. };
  180. } // namespace loc_util
  181. #endif // #ifndef __LOC_UNORDERDED_SETMAP_H__