123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- /* Copyright (c) 2015, 2017, 2020 The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of The Linux Foundation, nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
- #ifndef __LOC_UNORDERDED_SETMAP_H__
- #define __LOC_UNORDERDED_SETMAP_H__
- #include <algorithm>
- #include <loc_pla.h>
- #ifdef NO_UNORDERED_SET_OR_MAP
- #include <set>
- #include <map>
- #define unordered_set set
- #define unordered_map map
- #else
- #include <unordered_set>
- #include <unordered_map>
- #endif
- using std::unordered_set;
- using std::unordered_map;
- namespace loc_util {
- // Trim from *fromSet* any elements that also exist in *rVals*.
- // The optional *goneVals*, if not null, will be populated with removed elements.
- template <typename T>
- inline static void trimSet(unordered_set<T>& fromSet, const unordered_set<T>& rVals,
- unordered_set<T>* goneVals) {
- for (auto val : rVals) {
- if (fromSet.erase(val) > 0 && nullptr != goneVals) {
- goneVals->insert(val);
- }
- }
- }
- // this method is destructive to the input unordered_sets.
- // the return set is the interset extracted out from the two input sets, *s1* and *s2*.
- // *s1* and *s2* will be left with the intersect removed from them.
- template <typename T>
- static unordered_set<T> removeAndReturnInterset(unordered_set<T>& s1, unordered_set<T>& s2) {
- unordered_set<T> common = {};
- for (auto b = s2.begin(); b != s2.end(); b++) {
- auto a = find(s1.begin(), s1.end(), *b);
- if (a != s1.end()) {
- // this is a common item of both l1 and l2, remove from both
- // but after we add to common
- common.insert(*a);
- s1.erase(a);
- s2.erase(b);
- }
- }
- return common;
- }
- template <typename KEY, typename VAL>
- class LocUnorderedSetMap {
- unordered_map<KEY, unordered_set<VAL>> mMap;
- // Trim the VALs pointed to by *iter*, with everything that also exist in *rVals*.
- // If the set becomes empty, remove the map entry. *goneVals*, if not null, records
- // the trimmed VALs.
- bool trimOrRemove(typename unordered_map<KEY, unordered_set<VAL>>::iterator iter,
- const unordered_set<VAL>& rVals, unordered_set<VAL>* goneVals) {
- trimSet<VAL>(iter->second, rVals, goneVals);
- bool removeEntry = (iter->second.empty());
- if (removeEntry) {
- mMap.erase(iter);
- }
- return removeEntry;
- }
- public:
- inline LocUnorderedSetMap() {}
- inline LocUnorderedSetMap(size_t size) : LocUnorderedSetMap() {
- mMap.get_allocator().allocate(size);
- }
- inline bool empty() { return mMap.empty(); }
- // This gets the raw pointer to the VALs pointed to by *key*
- // If the entry is not in the map, nullptr will be returned.
- inline unordered_set<VAL>* getValSetPtr(const KEY& key) {
- auto entry = mMap.find(key);
- return (entry != mMap.end()) ? &(entry->second) : nullptr;
- }
- // This gets a copy of VALs pointed to by *key*
- // If the entry is not in the map, an empty set will be returned.
- inline unordered_set<VAL> getValSet(const KEY& key) {
- auto entry = mMap.find(key);
- return (entry != mMap.end()) ? entry->second : unordered_set<VAL>{};
- }
- // This gets all the KEYs from the map
- inline unordered_set<KEY> getKeys() {
- unordered_set<KEY> keys = {};
- for (auto entry : mMap) {
- keys.insert(entry.first);
- }
- return keys;
- }
- inline bool remove(const KEY& key) {
- return mMap.erase(key) > 0;
- }
- // This looks into all the entries keyed by *keys*. Remove any VALs from the entries
- // that also exist in *rVals*. If the entry is left with an empty set, the entry will
- // be removed. The optional parameters *goneKeys* and *goneVals* will record the KEYs
- // (or entries) and the collapsed VALs removed from the map, respectively.
- inline void trimOrRemove(unordered_set<KEY>&& keys, const unordered_set<VAL>& rVals,
- unordered_set<KEY>* goneKeys, unordered_set<VAL>* goneVals) {
- trimOrRemove(keys, rVals, goneKeys, goneVals);
- }
- inline void trimOrRemove(unordered_set<KEY>& keys, const unordered_set<VAL>& rVals,
- unordered_set<KEY>* goneKeys, unordered_set<VAL>* goneVals) {
- for (auto key : keys) {
- auto iter = mMap.find(key);
- if (iter != mMap.end() && trimOrRemove(iter, rVals, goneVals) && nullptr != goneKeys) {
- goneKeys->insert(iter->first);
- }
- }
- }
- // This adds all VALs from *newVals* to the map entry keyed by *key*. Or if it
- // doesn't exist yet, add the set to the map.
- bool add(const KEY& key, const unordered_set<VAL>& newVals) {
- bool newEntryAdded = false;
- if (!newVals.empty()) {
- auto iter = mMap.find(key);
- if (iter != mMap.end()) {
- iter->second.insert(newVals.begin(), newVals.end());
- } else {
- mMap[key] = newVals;
- newEntryAdded = true;
- }
- }
- return newEntryAdded;
- }
- // This adds to each of entries in the map keyed by *keys* with the VALs in the
- // *enwVals*. If there new entries added (new key in *keys*), *newKeys*, if not
- // null, would be populated with those keys.
- inline void add(const unordered_set<KEY>& keys, const unordered_set<VAL>&& newVals,
- unordered_set<KEY>* newKeys) {
- add(keys, newVals, newKeys);
- }
- inline void add(const unordered_set<KEY>& keys, const unordered_set<VAL>& newVals,
- unordered_set<KEY>* newKeys) {
- for (auto key : keys) {
- if (add(key, newVals) && nullptr != newKeys) {
- newKeys->insert(key);
- }
- }
- }
- // This puts *newVals* into the map keyed by *key*, and returns the VALs that are
- // in effect removed from the keyed VAL set in the map entry.
- // This call would also remove those same VALs from *newVals*.
- inline unordered_set<VAL> update(const KEY& key, unordered_set<VAL>& newVals) {
- unordered_set<VAL> goneVals = {};
- if (newVals.empty()) {
- mMap.erase(key);
- } else {
- auto curVals = mMap[key];
- mMap[key] = newVals;
- goneVals = removeAndReturnInterset(curVals, newVals);
- }
- return goneVals;
- }
- };
- } // namespace loc_util
- #endif // #ifndef __LOC_UNORDERDED_SETMAP_H__
|