diff options
-rw-r--r-- | core/Android.mk | 3 | ||||
-rw-r--r-- | core/Makefile.am | 3 | ||||
-rw-r--r-- | core/SystemStatus.cpp | 4 | ||||
-rw-r--r-- | core/SystemStatusOsObserver.cpp | 635 | ||||
-rw-r--r-- | core/SystemStatusOsObserver.h | 94 | ||||
-rw-r--r-- | core/data-items/common/ClientIndex.cpp | 172 | ||||
-rw-r--r-- | core/data-items/common/DataItemIndex.cpp | 203 | ||||
-rw-r--r-- | core/data-items/common/IClientIndex.h | 83 | ||||
-rw-r--r-- | core/data-items/common/IDataItemIndex.h | 94 | ||||
-rw-r--r-- | core/data-items/common/IndexFactory.cpp | 64 | ||||
-rw-r--r-- | core/data-items/common/IndexFactory.h | 48 | ||||
-rw-r--r-- | utils/LocListMap.h | 70 | ||||
-rw-r--r-- | utils/LocUnorderedSetMap.h | 196 |
13 files changed, 494 insertions, 1175 deletions
diff --git a/core/Android.mk b/core/Android.mk index d922766..1a4f51a 100644 --- a/core/Android.mk +++ b/core/Android.mk @@ -30,9 +30,6 @@ LOCAL_SRC_FILES += \ LocDualContext.cpp \ loc_core_log.cpp \ data-items/DataItemsFactoryProxy.cpp \ - data-items/common/ClientIndex.cpp \ - data-items/common/DataItemIndex.cpp \ - data-items/common/IndexFactory.cpp \ SystemStatusOsObserver.cpp \ SystemStatus.cpp diff --git a/core/Makefile.am b/core/Makefile.am index 78ae76b..cf8d9ff 100644 --- a/core/Makefile.am +++ b/core/Makefile.am @@ -38,9 +38,6 @@ libloc_core_la_c_sources = \ LocDualContext.cpp \ loc_core_log.cpp \ data-items/DataItemsFactoryProxy.cpp \ - data-items/common/ClientIndex.cpp \ - data-items/common/DataItemIndex.cpp \ - data-items/common/IndexFactory.cpp \ SystemStatusOsObserver.cpp \ SystemStatus.cpp diff --git a/core/SystemStatus.cpp b/core/SystemStatus.cpp index 6eb9968..e12d9f3 100644 --- a/core/SystemStatus.cpp +++ b/core/SystemStatus.cpp @@ -1694,9 +1694,7 @@ bool SystemStatus::eventConnectionStatus(bool connected, int8_t type) // send networkinof dataitem to systemstatus observer clients SystemStatusNetworkInfo s(type, "", "", false, connected, false); - list<IDataItemCore*> dl(0); - dl.push_back(&s); - mSysStatusObsvr.notify(dl); + mSysStatusObsvr.notify({&s}); } return true; } diff --git a/core/SystemStatusOsObserver.cpp b/core/SystemStatusOsObserver.cpp index 2fdd19f..0f6d228 100644 --- a/core/SystemStatusOsObserver.cpp +++ b/core/SystemStatusOsObserver.cpp @@ -32,28 +32,20 @@ #include <SystemStatus.h> #include <SystemStatusOsObserver.h> #include <IDataItemCore.h> -#include <IClientIndex.h> -#include <IDataItemIndex.h> -#include <IndexFactory.h> #include <DataItemsFactoryProxy.h> namespace loc_core { -SystemStatusOsObserver::SystemStatusOsObserver( - SystemStatus* systemstatus, const MsgTask* msgTask) : - mSystemStatus(systemstatus), - mAddress("SystemStatusOsObserver"), -#ifdef USE_GLIB - mBackHaulConnectReqCount(0), -#endif - mClientIndex(IndexFactory<IDataItemObserver*, DataItemId> :: createClientIndex()), - mDataItemIndex(IndexFactory<IDataItemObserver*, DataItemId> :: createDataItemIndex()) -{ - mContext.mMsgTask = msgTask; +template <typename CINT, typename COUT> +COUT SystemStatusOsObserver::containerTransfer(CINT& inContainer) { + COUT outContainer(0); + for (auto item : inContainer) { + outContainer.insert(outContainer.begin(), item); + } + return outContainer; } -SystemStatusOsObserver::~SystemStatusOsObserver() -{ +SystemStatusOsObserver::~SystemStatusOsObserver() { // Close data-item library handle DataItemsFactoryProxy::closeDataItemLibraryHandle(); @@ -65,290 +57,238 @@ SystemStatusOsObserver::~SystemStatusOsObserver() } mDataItemCache.clear(); - delete mClientIndex; - delete mDataItemIndex; } void SystemStatusOsObserver::setSubscriptionObj(IDataItemSubscription* subscriptionObj) { - mContext.mSubscriptionObj = subscriptionObj; - - LOC_LOGD("Request cache size - Subscribe:%zu RequestData:%zu", - mSubscribeReqCache.size(), mReqDataCache.size()); - - // we have received the subscription object. process cached requests - // process - subscribe request cache - for (auto each : mSubscribeReqCache) { - subscribe(each.second, each.first); - } - // process - requestData request cache - for (auto each : mReqDataCache) { - requestData(each.second, each.first); - } -} - -// Helper to cache requests subscribe and requestData till subscription obj is obtained -void SystemStatusOsObserver::cacheObserverRequest(ObserverReqCache& reqCache, - const list<DataItemId>& l, IDataItemObserver* client) -{ - ObserverReqCache::iterator dicIter = reqCache.find(client); - if (dicIter != reqCache.end()) { - // found - list<DataItemId> difference(0); - set_difference(l.begin(), l.end(), - dicIter->second.begin(), dicIter->second.end(), - inserter(difference, difference.begin())); - if (!difference.empty()) { - difference.sort(); - dicIter->second.merge(difference); - dicIter->second.unique(); + struct SetSubsObj : public LocMsg { + ObserverContext& mContext; + IDataItemSubscription* mSubsObj; + inline SetSubsObj(ObserverContext& context, IDataItemSubscription* subscriptionObj) : + mContext(context), mSubsObj(subscriptionObj) {} + void proc() const { + mContext.mSubscriptionObj = mSubsObj; + + if (!mContext.mSSObserver->mDataItemToClients.empty()) { + list<DataItemId> dis( + containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( + mContext.mSSObserver->mDataItemToClients.getKeys())); + mContext.mSubscriptionObj->subscribe(dis, mContext.mSSObserver); + mContext.mSubscriptionObj->requestData(dis, mContext.mSSObserver); + } } - } - else { - // not found - reqCache[client] = l; + }; + + if (nullptr == subscriptionObj) { + LOC_LOGw("subscriptionObj is NULL"); + } else { + mContext.mMsgTask->sendMsg(new SetSubsObj(mContext, subscriptionObj)); } } /****************************************************************************** IDataItemSubscription Overrides ******************************************************************************/ -void SystemStatusOsObserver::subscribe( - const list<DataItemId>& l, IDataItemObserver* client) +void SystemStatusOsObserver::subscribe(const list<DataItemId>& l, IDataItemObserver* client, + bool toRequestData) { - if (nullptr == mContext.mSubscriptionObj) { - LOC_LOGD("%s]: Subscription object is NULL. Caching requests", __func__); - cacheObserverRequest(mSubscribeReqCache, l, client); - return; - } - struct HandleSubscribeReq : public LocMsg { - HandleSubscribeReq(SystemStatusOsObserver* parent, - const list<DataItemId>& l, IDataItemObserver* client) : - mParent(parent), mClient(client), mDataItemList(l) {} - virtual ~HandleSubscribeReq() {} - void proc() const { + inline HandleSubscribeReq(SystemStatusOsObserver* parent, + list<DataItemId>& l, IDataItemObserver* client, bool requestData) : + mParent(parent), mClient(client), + mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)), + mToRequestData(requestData) {} - if (mDataItemList.empty()) { - LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); - return; - } - - // Handle First Response - list<DataItemId> pendingFirstResponseList(0); - mParent->mClientIndex->add(mClient, mDataItemList, pendingFirstResponseList); - - // Do not send first response for only pendingFirstResponseList, - // instead send for all the data items (present in the cache) that - // have been subscribed for each time. - mParent->sendFirstResponse(mDataItemList, mClient); + void proc() const { + unordered_set<DataItemId> dataItemsToSubscribe(0); + mParent->mDataItemToClients.add(mDataItemSet, {mClient}, &dataItemsToSubscribe); + mParent->mClientToDataItems.add(mClient, mDataItemSet); - list<DataItemId> yetToSubscribeDataItemsList(0); - mParent->mDataItemIndex->add(mClient, mDataItemList, yetToSubscribeDataItemsList); + mParent->sendCachedDataItems(mDataItemSet, mClient); - // Send subscription list to framework - if (!yetToSubscribeDataItemsList.empty()) { - mParent->mContext.mSubscriptionObj->subscribe(yetToSubscribeDataItemsList, mParent); + // Send subscription set to framework + if (nullptr != mParent->mContext.mSubscriptionObj && !dataItemsToSubscribe.empty()) { LOC_LOGD("Subscribe Request sent to framework for the following"); - mParent->logMe(yetToSubscribeDataItemsList); + mParent->logMe(dataItemsToSubscribe); + + if (mToRequestData) { + mParent->mContext.mSubscriptionObj->requestData( + containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( + std::move(dataItemsToSubscribe)), + mParent); + } else { + mParent->mContext.mSubscriptionObj->subscribe( + containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( + std::move(dataItemsToSubscribe)), + mParent); + } } } - SystemStatusOsObserver* mParent; + mutable SystemStatusOsObserver* mParent; IDataItemObserver* mClient; - const list<DataItemId> mDataItemList; + const unordered_set<DataItemId> mDataItemSet; + bool mToRequestData; }; - mContext.mMsgTask->sendMsg(new (nothrow) HandleSubscribeReq(this, l, client)); + + if (l.empty() || nullptr == client) { + LOC_LOGw("Data item set is empty or client is nullptr"); + } else { + mContext.mMsgTask->sendMsg( + new HandleSubscribeReq(this, (list<DataItemId>&)l, client, toRequestData)); + } } void SystemStatusOsObserver::updateSubscription( const list<DataItemId>& l, IDataItemObserver* client) { - if (nullptr == mContext.mSubscriptionObj) { - LOC_LOGE("%s:%d]: Subscription object is NULL", __func__, __LINE__); - return; - } - struct HandleUpdateSubscriptionReq : public LocMsg { HandleUpdateSubscriptionReq(SystemStatusOsObserver* parent, - const list<DataItemId>& l, IDataItemObserver* client) : - mParent(parent), mClient(client), mDataItemList(l) {} - virtual ~HandleUpdateSubscriptionReq() {} - void proc() const { - if (mDataItemList.empty()) { - LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); - return; - } + list<DataItemId>& l, IDataItemObserver* client) : + mParent(parent), mClient(client), + mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)) {} - list<DataItemId> currentlySubscribedList(0); - mParent->mClientIndex->getSubscribedList(mClient, currentlySubscribedList); - - list<DataItemId> removeDataItemList(0); - set_difference(currentlySubscribedList.begin(), currentlySubscribedList.end(), - mDataItemList.begin(), mDataItemList.end(), - inserter(removeDataItemList,removeDataItemList.begin())); - - // Handle First Response - list<DataItemId> pendingFirstResponseList(0); - mParent->mClientIndex->add(mClient, mDataItemList, pendingFirstResponseList); + void proc() const { + unordered_set<DataItemId> dataItemsToSubscribe(0); + unordered_set<DataItemId> dataItemsToUnsubscribe(0); + unordered_set<IDataItemObserver*> clients({mClient}); + // below removes clients from all entries keyed with the return of the + // mClientToDataItems.update() call. If leaving an empty set of clients as the + // result, the entire entry will be removed. dataItemsToUnsubscribe will be + // populated to keep the keys of the removed entries. + mParent->mDataItemToClients.trimOrRemove( + // this call updates <IDataItemObserver*, DataItemId> map; removes + // the DataItemId's that are not new to the clietn from mDataItemSet; + // and returns a set of mDataItemSet's that are no longer used by client. + // This unused set of mDataItemSet's is passed to trimOrRemove method of + // <DataItemId, IDataItemObserver*> map to remove the client from the + // corresponding entries, and gets a set of the entries that are + // removed from the <DataItemId, IDataItemObserver*> map as a result. + mParent->mClientToDataItems.update(mClient, + (unordered_set<DataItemId>&)mDataItemSet), + clients, &dataItemsToUnsubscribe, nullptr); + // below adds mClient to <DataItemId, IDataItemObserver*> map, and populates + // new keys added to that map, which are DataItemIds to be subscribed. + mParent->mDataItemToClients.add(mDataItemSet, clients, &dataItemsToSubscribe); // Send First Response - mParent->sendFirstResponse(pendingFirstResponseList, mClient); - - list<DataItemId> yetToSubscribeDataItemsList(0); - mParent->mDataItemIndex->add( - mClient, mDataItemList, yetToSubscribeDataItemsList); - - // Send subscription list to framework - if (!yetToSubscribeDataItemsList.empty()) { - mParent->mContext.mSubscriptionObj->subscribe( - yetToSubscribeDataItemsList, mParent); - LOC_LOGD("Subscribe Request sent to framework for the following"); - mParent->logMe(yetToSubscribeDataItemsList); - } - - list<DataItemId> unsubscribeList(0); - list<DataItemId> unused(0); - mParent->mClientIndex->remove(mClient, removeDataItemList, unused); + mParent->sendCachedDataItems(mDataItemSet, mClient); + + if (nullptr != mParent->mContext.mSubscriptionObj) { + // Send subscription set to framework + if (!dataItemsToSubscribe.empty()) { + LOC_LOGD("Subscribe Request sent to framework for the following"); + mParent->logMe(dataItemsToSubscribe); + + mParent->mContext.mSubscriptionObj->subscribe( + containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( + std::move(dataItemsToSubscribe)), + mParent); + } - if (!mParent->mClientIndex->isSubscribedClient(mClient)) { - mParent->mDataItemIndex->remove( - list<IDataItemObserver*> (1,mClient), unsubscribeList); - } - if (!unsubscribeList.empty()) { // Send unsubscribe to framework - mParent->mContext.mSubscriptionObj->unsubscribe(unsubscribeList, mParent); - LOC_LOGD("Unsubscribe Request sent to framework for the following"); - mParent->logMe(unsubscribeList); + if (!dataItemsToUnsubscribe.empty()) { + LOC_LOGD("Unsubscribe Request sent to framework for the following"); + mParent->logMe(dataItemsToUnsubscribe); + + mParent->mContext.mSubscriptionObj->unsubscribe( + containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( + std::move(dataItemsToUnsubscribe)), + mParent); + } } } SystemStatusOsObserver* mParent; IDataItemObserver* mClient; - const list<DataItemId> mDataItemList; + unordered_set<DataItemId> mDataItemSet; }; - mContext.mMsgTask->sendMsg(new (nothrow) HandleUpdateSubscriptionReq(this, l, client)); -} -void SystemStatusOsObserver::requestData( - const list<DataItemId>& l, IDataItemObserver* client) -{ - if (nullptr == mContext.mSubscriptionObj) { - LOC_LOGD("%s]: Subscription object is NULL. Caching requests", __func__); - cacheObserverRequest(mReqDataCache, l, client); - return; + if (l.empty() || nullptr == client) { + LOC_LOGw("Data item set is empty or client is nullptr"); + } else { + mContext.mMsgTask->sendMsg( + new HandleUpdateSubscriptionReq(this, (list<DataItemId>&)l, client)); } - - struct HandleRequestData : public LocMsg { - HandleRequestData(SystemStatusOsObserver* parent, - const list<DataItemId>& l, IDataItemObserver* client) : - mParent(parent), mClient(client), mDataItemList(l) {} - virtual ~HandleRequestData() {} - void proc() const { - if (mDataItemList.empty()) { - LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); - return; - } - - list<DataItemId> yetToSubscribeDataItemsList(0); - mParent->mClientIndex->add( - mClient, mDataItemList, yetToSubscribeDataItemsList); - mParent->mDataItemIndex->add( - mClient, mDataItemList, yetToSubscribeDataItemsList); - - // Send subscription list to framework - if (!mDataItemList.empty()) { - mParent->mContext.mSubscriptionObj->requestData(mDataItemList, mParent); - LOC_LOGD("Subscribe Request sent to framework for the following"); - mParent->logMe(yetToSubscribeDataItemsList); - } - } - SystemStatusOsObserver* mParent; - IDataItemObserver* mClient; - const list<DataItemId> mDataItemList; - }; - mContext.mMsgTask->sendMsg(new (nothrow) HandleRequestData(this, l, client)); } void SystemStatusOsObserver::unsubscribe( const list<DataItemId>& l, IDataItemObserver* client) { - if (nullptr == mContext.mSubscriptionObj) { - LOC_LOGE("%s:%d]: Subscription object is NULL", __func__, __LINE__); - return; - } struct HandleUnsubscribeReq : public LocMsg { HandleUnsubscribeReq(SystemStatusOsObserver* parent, - const list<DataItemId>& l, IDataItemObserver* client) : - mParent(parent), mClient(client), mDataItemList(l) {} - virtual ~HandleUnsubscribeReq() {} - void proc() const { - if (mDataItemList.empty()) { - LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); - return; - } + list<DataItemId>& l, IDataItemObserver* client) : + mParent(parent), mClient(client), + mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)) {} - list<DataItemId> unsubscribeList(0); - list<DataItemId> unused(0); - mParent->mClientIndex->remove(mClient, mDataItemList, unused); - - for (auto each : mDataItemList) { - list<IDataItemObserver*> clientListSubs(0); - list<IDataItemObserver*> clientListOut(0); - mParent->mDataItemIndex->remove( - each, list<IDataItemObserver*> (1,mClient), clientListOut); - // check if there are any other subscribed client for this data item id - mParent->mDataItemIndex->getListOfSubscribedClients(each, clientListSubs); - if (clientListSubs.empty()) - { - LOC_LOGD("Client list subscribed is empty for dataitem - %d", each); - unsubscribeList.push_back(each); - } - } + void proc() const { + unordered_set<DataItemId> dataItemsUnusedByClient(0); + unordered_set<IDataItemObserver*> clientToRemove(0); + mParent->mClientToDataItems.trimOrRemove({mClient}, mDataItemSet, &clientToRemove, + &dataItemsUnusedByClient); + unordered_set<DataItemId> dataItemsToUnsubscribe(0); + mParent->mDataItemToClients.trimOrRemove(dataItemsUnusedByClient, {mClient}, + &dataItemsToUnsubscribe, nullptr); + + if (nullptr != mParent->mContext.mSubscriptionObj && !dataItemsToUnsubscribe.empty()) { + LOC_LOGD("Unsubscribe Request sent to framework for the following data items"); + mParent->logMe(dataItemsToUnsubscribe); - if (!unsubscribeList.empty()) { // Send unsubscribe to framework - mParent->mContext.mSubscriptionObj->unsubscribe(unsubscribeList, mParent); - LOC_LOGD("Unsubscribe Request sent to framework for the following data items"); - mParent->logMe(unsubscribeList); + mParent->mContext.mSubscriptionObj->unsubscribe( + containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( + std::move(dataItemsToUnsubscribe)), + mParent); } } SystemStatusOsObserver* mParent; IDataItemObserver* mClient; - const list<DataItemId> mDataItemList; + unordered_set<DataItemId> mDataItemSet; }; - mContext.mMsgTask->sendMsg(new (nothrow) HandleUnsubscribeReq(this, l, client)); + + if (l.empty() || nullptr == client) { + LOC_LOGw("Data item set is empty or client is nullptr"); + } else { + mContext.mMsgTask->sendMsg(new HandleUnsubscribeReq(this, (list<DataItemId>&)l, client)); + } } void SystemStatusOsObserver::unsubscribeAll(IDataItemObserver* client) { - if (nullptr == mContext.mSubscriptionObj) { - LOC_LOGE("%s:%d]: Subscription object is NULL", __func__, __LINE__); - return; - } - struct HandleUnsubscribeAllReq : public LocMsg { HandleUnsubscribeAllReq(SystemStatusOsObserver* parent, IDataItemObserver* client) : mParent(parent), mClient(client) {} - virtual ~HandleUnsubscribeAllReq() {} - void proc() const { - list<IDataItemObserver*> clients(1, mClient); - list<DataItemId> unsubscribeList(0); - if(0 == mParent->mClientIndex->remove(mClient)) { - return; - } - mParent->mDataItemIndex->remove(clients, unsubscribeList); - if (!unsubscribeList.empty()) { - // Send unsubscribe to framework - mParent->mContext.mSubscriptionObj->unsubscribe(unsubscribeList, mParent); - LOC_LOGD("Unsubscribe Request sent to framework for the following data items"); - mParent->logMe(unsubscribeList); + void proc() const { + unordered_set<DataItemId> diByClient = mParent->mClientToDataItems.getValSet(mClient); + if (!diByClient.empty()) { + unordered_set<DataItemId> dataItemsToUnsubscribe; + mParent->mClientToDataItems.remove(mClient); + mParent->mDataItemToClients.trimOrRemove(diByClient, {mClient}, + &dataItemsToUnsubscribe, nullptr); + + if (!dataItemsToUnsubscribe.empty() && + nullptr != mParent->mContext.mSubscriptionObj) { + + LOC_LOGD("Unsubscribe Request sent to framework for the following data items"); + mParent->logMe(dataItemsToUnsubscribe); + + // Send unsubscribe to framework + mParent->mContext.mSubscriptionObj->unsubscribe( + containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( + std::move(dataItemsToUnsubscribe)), + mParent); + } } } SystemStatusOsObserver* mParent; IDataItemObserver* mClient; }; - mContext.mMsgTask->sendMsg(new (nothrow) HandleUnsubscribeAllReq(this, client)); + + if (nullptr == client) { + LOC_LOGw("Data item set is empty or client is nullptr"); + } else { + mContext.mMsgTask->sendMsg(new HandleUnsubscribeAllReq(this, client)); + } } /****************************************************************************** @@ -356,84 +296,78 @@ void SystemStatusOsObserver::unsubscribeAll(IDataItemObserver* client) ******************************************************************************/ void SystemStatusOsObserver::notify(const list<IDataItemCore*>& dlist) { - list<IDataItemCore*> dataItemList(0); - - for (auto each : dlist) { - string dv; - each->stringify(dv); - LOC_LOGD("notify: DataItem In Value:%s", dv.c_str()); - - IDataItemCore* di = DataItemsFactoryProxy::createNewDataItem(each->getId()); - if (nullptr == di) { - LOC_LOGE("Unable to create dataitem:%d", each->getId()); - return; - } - - // Copy contents into the newly created data item - di->copy(each); - - // Request systemstatus to record this dataitem in its cache - if (mSystemStatus->eventDataItemNotify(di)) { - // add this dataitem if updated from last one - dataItemList.push_back(di); - } - } - struct HandleNotify : public LocMsg { - HandleNotify(SystemStatusOsObserver* parent, const list<IDataItemCore*>& l) : - mParent(parent), mDList(l) {} - virtual ~HandleNotify() { - for (auto each : mDList) { - delete each; + HandleNotify(SystemStatusOsObserver* parent, vector<IDataItemCore*>& v) : + mParent(parent), mDiVec(std::move(v)) {} + + inline virtual ~HandleNotify() { + for (auto item : mDiVec) { + delete item; } } + void proc() const { // Update Cache with received data items and prepare // list of data items to be sent. - list<DataItemId> dataItemIdsToBeSent(0); - for (auto item : mDList) { - bool dataItemUpdated = false; - mParent->updateCache(item, dataItemUpdated); - if (dataItemUpdated) { - dataItemIdsToBeSent.push_back(item->getId()); + unordered_set<DataItemId> dataItemIdsToBeSent(0); + for (auto item : mDiVec) { + if (mParent->updateCache(item)) { + dataItemIdsToBeSent.insert(item->getId()); } } // Send data item to all subscribed clients - list<IDataItemObserver*> clientList(0); + unordered_set<IDataItemObserver*> clientSet(0); for (auto each : dataItemIdsToBeSent) { - list<IDataItemObserver*> clients(0); - mParent->mDataItemIndex->getListOfSubscribedClients(each, clients); - for (auto each_cient: clients) { - clientList.push_back(each_cient); + auto clients = mParent->mDataItemToClients.getValSetPtr(each); + if (nullptr != clients) { + clientSet.insert(clients->begin(), clients->end()); } } - clientList.unique(); - - for (auto client : clientList) { - list<DataItemId> dataItemIdsSubscribedByThisClient(0); - list<DataItemId> dataItemIdsToBeSentForThisClient(0); - mParent->mClientIndex->getSubscribedList( - client, dataItemIdsSubscribedByThisClient); - dataItemIdsSubscribedByThisClient.sort(); - dataItemIdsToBeSent.sort(); - - set_intersection(dataItemIdsToBeSent.begin(), - dataItemIdsToBeSent.end(), - dataItemIdsSubscribedByThisClient.begin(), - dataItemIdsSubscribedByThisClient.end(), - inserter(dataItemIdsToBeSentForThisClient, - dataItemIdsToBeSentForThisClient.begin())); - - mParent->sendCachedDataItems(dataItemIdsToBeSentForThisClient, client); - dataItemIdsSubscribedByThisClient.clear(); - dataItemIdsToBeSentForThisClient.clear(); + + for (auto client : clientSet) { + unordered_set<DataItemId> dataItemIdsForThisClient( + mParent->mClientToDataItems.getValSet(client)); + for (auto id : dataItemIdsForThisClient) { + if (dataItemIdsToBeSent.find(id) == dataItemIdsToBeSent.end()) { + dataItemIdsForThisClient.erase(id); + } + } + + mParent->sendCachedDataItems(dataItemIdsForThisClient, client); } } SystemStatusOsObserver* mParent; - const list<IDataItemCore*> mDList; + const vector<IDataItemCore*> mDiVec; }; - mContext.mMsgTask->sendMsg(new (nothrow) HandleNotify(this, dataItemList)); + + if (!dlist.empty()) { + vector<IDataItemCore*> dataItemVec(dlist.size()); + + for (auto each : dlist) { + IF_LOC_LOGD { + string dv; + each->stringify(dv); + LOC_LOGD("notify: DataItem In Value:%s", dv.c_str()); + } + + IDataItemCore* di = DataItemsFactoryProxy::createNewDataItem(each->getId()); + if (nullptr == di) { + LOC_LOGw("Unable to create dataitem:%d", each->getId()); + continue; + } + + // Copy contents into the newly created data item + di->copy(each); + + // add this dataitem if updated from last one + dataItemVec.push_back(di); + } + + if (!dataItemVec.empty()) { + mContext.mMsgTask->sendMsg(new HandleNotify(this, dataItemVec)); + } + } } /****************************************************************************** @@ -447,7 +381,7 @@ void SystemStatusOsObserver::turnOn(DataItemId dit, int timeOut) } // Check if data item exists in mActiveRequestCount - map<DataItemId, int>::iterator citer = mActiveRequestCount.find(dit); + DataItemIdToInt::iterator citer = mActiveRequestCount.find(dit); if (citer == mActiveRequestCount.end()) { // Data item not found in map // Add reference count as 1 and add dataitem to map @@ -485,7 +419,7 @@ void SystemStatusOsObserver::turnOff(DataItemId dit) } // Check if data item exists in mActiveRequestCount - map<DataItemId, int>::iterator citer = mActiveRequestCount.find(dit); + DataItemIdToInt::iterator citer = mActiveRequestCount.find(dit); if (citer != mActiveRequestCount.end()) { // found citer->second--; @@ -573,84 +507,65 @@ bool SystemStatusOsObserver::disconnectBackhaul() /****************************************************************************** Helpers ******************************************************************************/ -void SystemStatusOsObserver::sendFirstResponse( - const list<DataItemId>& l, IDataItemObserver* to) +void SystemStatusOsObserver::sendCachedDataItems( + const unordered_set<DataItemId>& s, IDataItemObserver* to) { - if (l.empty()) { - LOC_LOGV("list is empty. Nothing to do. Exiting"); - return; - } - - string clientName; - to->getName(clientName); - list<IDataItemCore*> dataItems(0); - - for (auto each : l) { - map<DataItemId, IDataItemCore*>::const_iterator citer = mDataItemCache.find(each); - if (citer != mDataItemCache.end()) { - string dv; - citer->second->stringify(dv); - LOC_LOGI("DataItem: %s >> %s", dv.c_str(), clientName.c_str()); - dataItems.push_back(citer->second); + if (nullptr == to) { + LOC_LOGv("client pointer is NULL."); + } else { + string clientName; + to->getName(clientName); + list<IDataItemCore*> dataItems(0); + + for (auto each : s) { + auto citer = mDataItemCache.find(each); + if (citer != mDataItemCache.end()) { + string dv; + citer->second->stringify(dv); + LOC_LOGI("DataItem: %s >> %s", dv.c_str(), clientName.c_str()); + dataItems.push_front(citer->second); + } } - } - if (dataItems.empty()) { - LOC_LOGV("No items to notify. Nothing to do. Exiting"); - return; - } - to->notify(dataItems); -} -void SystemStatusOsObserver::sendCachedDataItems( - const list<DataItemId>& l, IDataItemObserver* to) -{ - string clientName; - to->getName(clientName); - list<IDataItemCore*> dataItems(0); - - for (auto each : l) { - string dv; - IDataItemCore* di = mDataItemCache[each]; - di->stringify(dv); - LOC_LOGI("DataItem: %s >> %s", dv.c_str(), clientName.c_str()); - dataItems.push_back(di); + if (dataItems.empty()) { + LOC_LOGv("No items to notify."); + } else { + to->notify(dataItems); + } } - to->notify(dataItems); } -void SystemStatusOsObserver::updateCache(IDataItemCore* d, bool& dataItemUpdated) +bool SystemStatusOsObserver::updateCache(IDataItemCore* d) { - if (nullptr == d) { - return; - } - - // Check if data item exists in cache - map<DataItemId, IDataItemCore*>::iterator citer = - mDataItemCache.find(d->getId()); - if (citer == mDataItemCache.end()) { - // New data item; not found in cache - IDataItemCore* dataitem = DataItemsFactoryProxy::createNewDataItem(d->getId()); - if (nullptr == dataitem) { - return; + bool dataItemUpdated = false; + + // Request systemstatus to record this dataitem in its cache + // if the return is false, it means that SystemStatus is not + // handling it, so SystemStatusOsObserver also doesn't. + // So it has to be true to proceed. + if (nullptr != d && mSystemStatus->eventDataItemNotify(d)) { + auto citer = mDataItemCache.find(d->getId()); + if (citer == mDataItemCache.end()) { + // New data item; not found in cache + IDataItemCore* dataitem = DataItemsFactoryProxy::createNewDataItem(d->getId()); + if (nullptr != dataitem) { + // Copy the contents of the data item + dataitem->copy(d); + // Insert in mDataItemCache + mDataItemCache.insert(std::make_pair(d->getId(), dataitem)); + dataItemUpdated = true; + } + } else { + // Found in cache; Update cache if necessary + citer->second->copy(d, &dataItemUpdated); } - // Copy the contents of the data item - dataitem->copy(d); - pair<DataItemId, IDataItemCore*> cpair(d->getId(), dataitem); - // Insert in mDataItemCache - mDataItemCache.insert(cpair); - dataItemUpdated = true; - } - else { - // Found in cache; Update cache if necessary - if(0 == citer->second->copy(d, &dataItemUpdated)) { - return; + if (dataItemUpdated) { + LOC_LOGV("DataItem:%d updated:%d", d->getId(), dataItemUpdated); } } - if (dataItemUpdated) { - LOC_LOGV("DataItem:%d updated:%d", d->getId(), dataItemUpdated); - } + return dataItemUpdated; } } // namespace loc_core diff --git a/core/SystemStatusOsObserver.h b/core/SystemStatusOsObserver.h index 930ddc1..fd60606 100644 --- a/core/SystemStatusOsObserver.h +++ b/core/SystemStatusOsObserver.h @@ -41,6 +41,7 @@ #include <IOsObserver.h> #include <loc_pla.h> #include <log_util.h> +#include <LocUnorderedSetMap.h> namespace loc_core { @@ -48,39 +49,57 @@ namespace loc_core SystemStatusOsObserver ******************************************************************************/ using namespace std; +using namespace loc_util; // Forward Declarations class IDataItemCore; -template<typename CT, typename DIT> class IClientIndex; -template<typename CT, typename DIT> class IDataItemIndex; +class SystemStatus; +class SystemStatusOsObserver; +typedef map<IDataItemObserver*, list<DataItemId>> ObserverReqCache; +typedef LocUnorderedSetMap<IDataItemObserver*, DataItemId> ClientToDataItems; +typedef LocUnorderedSetMap<DataItemId, IDataItemObserver*> DataItemToClients; +typedef unordered_map<DataItemId, IDataItemCore*> DataItemIdToCore; +typedef unordered_map<DataItemId, int> DataItemIdToInt; -struct SystemContext { +struct ObserverContext { IDataItemSubscription* mSubscriptionObj; IFrameworkActionReq* mFrameworkActionReqObj; const MsgTask* mMsgTask; + SystemStatusOsObserver* mSSObserver; - inline SystemContext() : - mSubscriptionObj(NULL), - mFrameworkActionReqObj(NULL), - mMsgTask(NULL) {} + inline ObserverContext(const MsgTask* msgTask, SystemStatusOsObserver* observer) : + mSubscriptionObj(NULL), mFrameworkActionReqObj(NULL), + mMsgTask(msgTask), mSSObserver(observer) {} }; -typedef map<IDataItemObserver*, list<DataItemId>> ObserverReqCache; - // Clients wanting to get data from OS/Framework would need to // subscribe with OSObserver using IDataItemSubscription interface. // Such clients would need to implement IDataItemObserver interface // to receive data when it becomes available. -class SystemStatus; class SystemStatusOsObserver : public IOsObserver { public: // ctor - SystemStatusOsObserver( - SystemStatus* systemstatus, const MsgTask* msgTask); + inline SystemStatusOsObserver(SystemStatus* systemstatus, const MsgTask* msgTask) : + mSystemStatus(systemstatus), mContext(msgTask, this), + mAddress("SystemStatusOsObserver"), + mClientToDataItems(MAX_DATA_ITEM_ID), mDataItemToClients(MAX_DATA_ITEM_ID) +#ifdef USE_GLIB + , mBackHaulConnectReqCount(0) +#endif + { + } + // dtor ~SystemStatusOsObserver(); + template <typename CINT, typename COUT> + static COUT containerTransfer(CINT& s); + template <typename CINT, typename COUT> + inline static COUT containerTransfer(CINT&& s) { + return containerTransfer<CINT, COUT>(s); + } + // To set the subscription object virtual void setSubscriptionObj(IDataItemSubscription* subscriptionObj); @@ -96,38 +115,40 @@ public: } // IDataItemSubscription Overrides - virtual void subscribe(const list<DataItemId>& l, IDataItemObserver* client); - virtual void updateSubscription(const list<DataItemId>& l, IDataItemObserver* client); - virtual void requestData(const list<DataItemId>& l, IDataItemObserver* client); - virtual void unsubscribe(const list<DataItemId>& l, IDataItemObserver* client); - virtual void unsubscribeAll(IDataItemObserver* client); + inline virtual void subscribe(const list<DataItemId>& l, IDataItemObserver* client) override { + subscribe(l, client, false); + } + virtual void updateSubscription(const list<DataItemId>& l, IDataItemObserver* client) override; + inline virtual void requestData(const list<DataItemId>& l, IDataItemObserver* client) override { + subscribe(l, client, true); + } + virtual void unsubscribe(const list<DataItemId>& l, IDataItemObserver* client) override; + virtual void unsubscribeAll(IDataItemObserver* client) override; // IDataItemObserver Overrides - virtual void notify(const list<IDataItemCore*>& dlist); - inline virtual void getName(string& name) { + virtual void notify(const list<IDataItemCore*>& dlist) override; + inline virtual void getName(string& name) override { name = mAddress; } // IFrameworkActionReq Overrides - virtual void turnOn(DataItemId dit, int timeOut = 0); - virtual void turnOff(DataItemId dit); + virtual void turnOn(DataItemId dit, int timeOut = 0) override; + virtual void turnOff(DataItemId dit) override; #ifdef USE_GLIB - virtual bool connectBackhaul(); + virtual bool connectBackhaul() override; virtual bool disconnectBackhaul(); #endif private: SystemStatus* mSystemStatus; - SystemContext mContext; + ObserverContext mContext; const string mAddress; - IClientIndex<IDataItemObserver*, DataItemId>* mClientIndex; - IDataItemIndex<IDataItemObserver*, DataItemId>* mDataItemIndex; - map<DataItemId, IDataItemCore*> mDataItemCache; - map<DataItemId, int> mActiveRequestCount; + ClientToDataItems mClientToDataItems; + DataItemToClients mDataItemToClients; + DataItemIdToCore mDataItemCache; + DataItemIdToInt mActiveRequestCount; // Cache the subscribe and requestData till subscription obj is obtained - ObserverReqCache mSubscribeReqCache; - ObserverReqCache mReqDataCache; void cacheObserverRequest(ObserverReqCache& reqCache, const list<DataItemId>& l, IDataItemObserver* client); #ifdef USE_GLIB @@ -135,13 +156,16 @@ private: int mBackHaulConnectReqCount; #endif + void subscribe(const list<DataItemId>& l, IDataItemObserver* client, bool toRequestData); + // Helpers - void sendFirstResponse(const list<DataItemId>& l, IDataItemObserver* to); - void sendCachedDataItems(const list<DataItemId>& l, IDataItemObserver* to); - void updateCache(IDataItemCore* d, bool& dataItemUpdated); - inline void logMe(const list<DataItemId>& l) { - for (auto id : l) { - LOC_LOGD("DataItem %d", id); + void sendCachedDataItems(const unordered_set<DataItemId>& s, IDataItemObserver* to); + bool updateCache(IDataItemCore* d); + inline void logMe(const unordered_set<DataItemId>& l) { + IF_LOC_LOGD { + for (auto id : l) { + LOC_LOGD("DataItem %d", id); + } } } }; diff --git a/core/data-items/common/ClientIndex.cpp b/core/data-items/common/ClientIndex.cpp deleted file mode 100644 index d4bd11e..0000000 --- a/core/data-items/common/ClientIndex.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* Copyright (c) 2015, 2017 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. - * - */ -#include <algorithm> -#include <iterator> -#include <string> -#include <loc_pla.h> -#include <log_util.h> -#include <ClientIndex.h> -#include <IDataItemObserver.h> -#include <DataItemId.h> - -using namespace std; -using namespace loc_core; - -template <typename CT, typename DIT> -inline ClientIndex <CT,DIT> :: ClientIndex () {} - -template <typename CT, typename DIT> -inline ClientIndex <CT,DIT> :: ~ClientIndex () {} - -template <typename CT, typename DIT> -bool ClientIndex <CT,DIT> :: isSubscribedClient (CT client) { - bool result = false; - ENTRY_LOG (); - typename map < CT, list <DIT> > :: iterator it = - mDataItemsPerClientMap.find (client); - if (it != mDataItemsPerClientMap.end ()) { - result = true; - } - EXIT_LOG_WITH_ERROR ("%d",result); - return result; -} - -template <typename CT, typename DIT> -void ClientIndex <CT,DIT> :: getSubscribedList (CT client, list <DIT> & out) { - ENTRY_LOG (); - typename map < CT, list <DIT> > :: iterator it = - mDataItemsPerClientMap.find (client); - if (it != mDataItemsPerClientMap.end ()) { - out = it->second; - } - EXIT_LOG_WITH_ERROR ("%d",0); -} - -template <typename CT, typename DIT> -int ClientIndex <CT,DIT> :: remove (CT client) { - int result = 0; - ENTRY_LOG (); - mDataItemsPerClientMap.erase (client); - EXIT_LOG_WITH_ERROR ("%d",result); - return result; -} - -template <typename CT, typename DIT> -void ClientIndex <CT,DIT> :: remove (const list <DIT> & r, list <CT> & out) { - ENTRY_LOG (); - typename map < CT, list <DIT> > :: iterator dicIter = - mDataItemsPerClientMap.begin (); - while (dicIter != mDataItemsPerClientMap.end()) { - typename list <DIT> :: const_iterator it = r.begin (); - for (; it != r.end (); ++it) { - typename list <DIT> :: iterator iter = - find (dicIter->second.begin (), dicIter->second.end (), *it); - if (iter != dicIter->second.end ()) { - dicIter->second.erase (iter); - } - } - if (dicIter->second.empty ()) { - out.push_back (dicIter->first); - // Post-increment operator increases the iterator but returns the - // prevous one that will be invalidated by erase() - mDataItemsPerClientMap.erase (dicIter++); - } else { - ++dicIter; - } - } - EXIT_LOG_WITH_ERROR ("%d",0); -} - -template <typename CT, typename DIT> -void ClientIndex <CT,DIT> :: remove -( - CT client, - const list <DIT> & r, - list <DIT> & out -) -{ - ENTRY_LOG (); - typename map < CT, list <DIT> > :: iterator dicIter = - mDataItemsPerClientMap.find (client); - if (dicIter != mDataItemsPerClientMap.end ()) { - set_intersection (dicIter->second.begin (), dicIter->second.end (), - r.begin (), r.end (), - inserter (out,out.begin ())); - if (!out.empty ()) { - typename list <DIT> :: iterator it = out.begin (); - for (; it != out.end (); ++it) { - dicIter->second.erase (find (dicIter->second.begin (), - dicIter->second.end (), - *it)); - } - } - if (dicIter->second.empty ()) { - mDataItemsPerClientMap.erase (dicIter); - EXIT_LOG_WITH_ERROR ("%d",0); - } - } - EXIT_LOG_WITH_ERROR ("%d",0); -} - -template <typename CT, typename DIT> -void ClientIndex <CT,DIT> :: add -( - CT client, - const list <DIT> & l, - list <DIT> & out -) -{ - ENTRY_LOG (); - list <DIT> difference; - typename map < CT, list <DIT> > :: iterator dicIter = - mDataItemsPerClientMap.find (client); - if (dicIter != mDataItemsPerClientMap.end ()) { - set_difference (l.begin (), l.end (), - dicIter->second.begin (), dicIter->second.end (), - inserter (difference,difference.begin ())); - if (!difference.empty ()) { - difference.sort (); - out = difference; - dicIter->second.merge (difference); - dicIter->second.unique (); - } - } else { - out = l; - pair < CT, list <DIT> > dicnpair (client, out); - mDataItemsPerClientMap.insert (dicnpair); - } - EXIT_LOG_WITH_ERROR ("%d",0); -} - -// Explicit instantiation must occur in same namespace where class is defined -namespace loc_core -{ - template class ClientIndex <IDataItemObserver *, DataItemId>; - template class ClientIndex <string, DataItemId>; -} diff --git a/core/data-items/common/DataItemIndex.cpp b/core/data-items/common/DataItemIndex.cpp deleted file mode 100644 index 462bf74..0000000 --- a/core/data-items/common/DataItemIndex.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* Copyright (c) 2015, 2017 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. - * - */ - -#include <string> -#include <algorithm> -#include <iterator> -#include <DataItemIndex.h> -#include <loc_pla.h> -#include <log_util.h> -#include <IDataItemObserver.h> -#include <DataItemId.h> - -using namespace std; -using namespace loc_core; - -template <typename CT, typename DIT> -inline DataItemIndex <CT,DIT> :: DataItemIndex () {} - -template <typename CT, typename DIT> -inline DataItemIndex <CT,DIT> :: ~DataItemIndex () {} - -template <typename CT, typename DIT> -void DataItemIndex <CT,DIT> :: getListOfSubscribedClients - ( - DIT id, - list <CT> & out -) -{ - typename map < DIT, list <CT> > :: iterator cdiIter = - mClientsPerDataItemMap.find (id); - if (cdiIter != mClientsPerDataItemMap.end ()) { - out = cdiIter->second; - } -} - - -template <typename CT, typename DIT> -int DataItemIndex <CT,DIT> :: remove (DIT id) { - int result = 0; - ENTRY_LOG (); - mClientsPerDataItemMap.erase (id); - EXIT_LOG_WITH_ERROR ("%d",result); - return result; -} - -template <typename CT, typename DIT> -void DataItemIndex <CT,DIT> :: remove (const list <CT> & r, list <DIT> & out) { - ENTRY_LOG (); - typename map < DIT, list <CT> > :: iterator cdiIter = - mClientsPerDataItemMap.begin (); - while (cdiIter != mClientsPerDataItemMap.end()) { - typename list <CT> :: const_iterator it = r.begin (); - for (; it != r.end (); ++it) { - typename list <CT> :: iterator iter = - find - ( - cdiIter->second.begin (), - cdiIter->second.end (), - *it - ); - if (iter != cdiIter->second.end ()) { - cdiIter->second.erase (iter); - } - } - - if (cdiIter->second.empty ()) { - out.push_back (cdiIter->first); - // Post-increment operator increases the iterator but returns the - // prevous one that will be invalidated by erase() - mClientsPerDataItemMap.erase (cdiIter++); - } else { - ++cdiIter; - } - } - EXIT_LOG_WITH_ERROR ("%d",0); -} - -template <typename CT, typename DIT> -void DataItemIndex <CT,DIT> :: remove -( - DIT id, - const list <CT> & r, - list <CT> & out -) -{ - ENTRY_LOG (); - - typename map < DIT, list <CT> > :: iterator cdiIter = - mClientsPerDataItemMap.find (id); - if (cdiIter != mClientsPerDataItemMap.end ()) { - set_intersection (cdiIter->second.begin (), cdiIter->second.end (), - r.begin (), r.end (), - inserter (out, out.begin ())); - if (!out.empty ()) { - typename list <CT> :: iterator it = out.begin (); - for (; it != out.end (); ++it) { - cdiIter->second.erase (find (cdiIter->second.begin (), - cdiIter->second.end (), - *it)); - } - } - if (cdiIter->second.empty ()) { - mClientsPerDataItemMap.erase (cdiIter); - EXIT_LOG_WITH_ERROR ("%d",0); - } - } - EXIT_LOG_WITH_ERROR ("%d",0); -} - -template <typename CT, typename DIT> -void DataItemIndex <CT,DIT> :: add -( - DIT id, - const list <CT> & l, - list <CT> & out -) -{ - ENTRY_LOG (); - list <CT> difference; - typename map < DIT, list <CT> > :: iterator cdiIter = - mClientsPerDataItemMap.find (id); - if (cdiIter != mClientsPerDataItemMap.end ()) { - set_difference (l.begin (), l.end (), - cdiIter->second.begin (), cdiIter->second.end (), - inserter (difference, difference.begin ())); - if (!difference.empty ()) { - difference.sort (); - out = difference; - cdiIter->second.merge (difference); - } - } else { - out = l; - pair < DIT, list <CT> > cndipair (id, out); - mClientsPerDataItemMap.insert (cndipair); - } - EXIT_LOG_WITH_ERROR ("%d",0); -} - -template <typename CT, typename DIT> -void DataItemIndex <CT,DIT> :: add -( - CT client, - const list <DIT> & l, - list <DIT> & out -) -{ - ENTRY_LOG (); - typename map < DIT, list <CT> > :: iterator cdiIter; - typename list <DIT> :: const_iterator it = l.begin (); - for (; it != l.end (); ++it) { - cdiIter = mClientsPerDataItemMap.find (*it); - if (cdiIter == mClientsPerDataItemMap.end ()) { - out.push_back (*it); - pair < DIT, list <CT> > cndiPair (*it, list <CT> (1, client)); - mClientsPerDataItemMap.insert (cndiPair); - } else { - typename list<CT> :: iterator clientIter = - find - ( - cdiIter->second.begin (), - cdiIter->second.end (), - client - ); - if (clientIter == cdiIter->second.end()) { - cdiIter->second.push_back (client); - } - } - } - EXIT_LOG_WITH_ERROR ("%d",0); -} - -// Explicit instantiation must occur in same namespace where class is defined -namespace loc_core -{ - template class DataItemIndex <IDataItemObserver *, DataItemId>; - template class DataItemIndex <string, DataItemId>; -} diff --git a/core/data-items/common/IClientIndex.h b/core/data-items/common/IClientIndex.h deleted file mode 100644 index 0272e7b..0000000 --- a/core/data-items/common/IClientIndex.h +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright (c) 2015, 2017 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 __ICLIENTINDEX_H__ -#define __ICLIENTINDEX_H__ - -#include <list> - -namespace loc_core -{ - -template <typename CT, typename DIT> - -class IClientIndex { -public: - - // Checks if client is subscribed - virtual bool isSubscribedClient (CT client) = 0; - - // gets subscription list - virtual void getSubscribedList (CT client, std :: list <DIT> & out) = 0; - - // removes an entry - virtual int remove (CT client) = 0; - - // removes std :: list of data items and returns a list of clients - // removed if any. - virtual void remove - ( - const std :: list <DIT> & r, - std :: list <CT> & out - ) = 0; - - // removes list of data items indexed by client and returns list - // of data items removed if any. - virtual void remove - ( - CT client, - const std :: list <DIT> & r, - std :: list <DIT> & out - ) = 0; - - // adds/modifies entry in map and returns new data items added. - virtual void add - ( - CT client, - const std :: list <DIT> & l, - std :: list <DIT> & out - ) = 0; - - // dtor - virtual ~IClientIndex () {} -}; - -} // namespace loc_core - -#endif // #ifndef __ICLIENTINDEX_H__ diff --git a/core/data-items/common/IDataItemIndex.h b/core/data-items/common/IDataItemIndex.h deleted file mode 100644 index 9185582..0000000 --- a/core/data-items/common/IDataItemIndex.h +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (c) 2015, 2017 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 __IDATAITEMINDEX_H__ -#define __IDATAITEMINDEX_H__ - -#include <list> - -namespace loc_core -{ - -template <typename CT, typename DIT> - -class IDataItemIndex { - -public: - - // gets std :: list of subscribed clients - virtual void getListOfSubscribedClients - ( - DIT id, - std :: list <CT> & out - ) = 0; - - // removes an entry from - virtual int remove (DIT id) = 0; - - // removes list of clients and returns a list of data items - // removed if any. - virtual void remove - ( - const std :: list <CT> & r, - std :: list <DIT> & out - ) = 0; - - // removes list of clients indexed by data item and returns list of - // clients removed if any. - virtual void remove - ( - DIT id, - const std :: list <CT> & r, - std :: list <CT> & out - ) = 0; - - // adds/modifies entry and returns new clients added - virtual void add - ( - DIT id, - const std :: list <CT> & l, - std :: list <CT> & out - ) = 0; - - // adds/modifies entry and returns yet to subscribe list of data items - virtual void add - ( - CT client, - const std :: list <DIT> & l, - std :: list <DIT> & out - ) = 0; - - // dtor - virtual ~IDataItemIndex () {} -}; - -} // namespace loc_core - -#endif // #ifndef __IDATAITEMINDEX_H__ - diff --git a/core/data-items/common/IndexFactory.cpp b/core/data-items/common/IndexFactory.cpp deleted file mode 100644 index cf49475..0000000 --- a/core/data-items/common/IndexFactory.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (c) 2015, 2017 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. - * - */ - -#include <string> -#include <IndexFactory.h> -#include <IClientIndex.h> -#include <ClientIndex.h> -#include <IDataItemIndex.h> -#include <DataItemIndex.h> -#include <IDataItemObserver.h> -#include <DataItemId.h> - -using namespace std; -using loc_core::IClientIndex; -using loc_core::IDataItemIndex; -using loc_core::IDataItemObserver; -using namespace loc_core; - -template <typename CT, typename DIT> -inline IClientIndex <CT, DIT> * IndexFactory <CT, DIT> :: createClientIndex -() -{ - return new (nothrow) ClientIndex <CT, DIT> (); -} - -template <typename CT, typename DIT> -inline IDataItemIndex <CT, DIT> * IndexFactory <CT, DIT> :: createDataItemIndex -() -{ - return new (nothrow) DataItemIndex <CT, DIT> (); -} - -// Explicit instantiation must occur in same namespace where class is defined -namespace loc_core -{ - template class IndexFactory <IDataItemObserver *, DataItemId>; - template class IndexFactory <string, DataItemId>; -} diff --git a/core/data-items/common/IndexFactory.h b/core/data-items/common/IndexFactory.h deleted file mode 100644 index 9a2070e..0000000 --- a/core/data-items/common/IndexFactory.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (c) 2015, 2017 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 __INDEXFACTORY_H__ -#define __INDEXFACTORY_H__ - -#include <IClientIndex.h> -#include <IDataItemIndex.h> - -namespace loc_core -{ -template <typename CT, typename DIT> -class IndexFactory { - -public: - static IClientIndex <CT, DIT> * createClientIndex (); - static IDataItemIndex <CT, DIT> * createDataItemIndex (); -}; - -} // namespace loc_core - -#endif // #ifndef __INDEXFACTORY_H__ diff --git a/utils/LocListMap.h b/utils/LocListMap.h deleted file mode 100644 index feccb05..0000000 --- a/utils/LocListMap.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright (c) 2015, 2017 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 __CLIENTINDEX_H__ -#define __CLIENTINDEX_H__ - -#include <list> -#include <map> -#include <IClientIndex.h> - -using loc_core::IClientIndex; - -namespace loc_core -{ - -template <typename CT, typename DIT> - -class ClientIndex : public IClientIndex <CT, DIT> { - -public: - - ClientIndex (); - - ~ClientIndex (); - - bool isSubscribedClient (CT client); - - void getSubscribedList (CT client, std :: list <DIT> & out); - - int remove (CT client); - - void remove (const std :: list <DIT> & r, std :: list <CT> & out); - - void remove (CT client, const std :: list <DIT> & r, std :: list <DIT> & out); - - void add (CT client, const std :: list <DIT> & l, std :: list <DIT> & out); - -private: - //Data members - std :: map < CT , std :: list <DIT> > mDataItemsPerClientMap; -}; - -} // namespace loc_core - -#endif // #ifndef __CLIENTINDEX_H__ diff --git a/utils/LocUnorderedSetMap.h b/utils/LocUnorderedSetMap.h index d72e89e..8748134 100644 --- a/utils/LocUnorderedSetMap.h +++ b/utils/LocUnorderedSetMap.h @@ -26,45 +26,167 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ - -#ifndef __DATAITEMINDEX_H__ -#define __DATAITEMINDEX_H__ - -#include <list> -#include <map> -#include <IDataItemIndex.h> - -using loc_core::IDataItemIndex; - -namespace loc_core -{ - -template <typename CT, typename DIT> - -class DataItemIndex : public IDataItemIndex <CT, DIT> { +#ifndef __LOC_UNORDERDED_SETMAP_H__ +#define __LOC_UNORDERDED_SETMAP_H__ + +#include <algorithm> +#include <unordered_set> +#include <unordered_map> + +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(0); + 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: - - DataItemIndex (); - - ~DataItemIndex (); - - void getListOfSubscribedClients (DIT id, std :: list <CT> & out); - - int remove (DIT id); - - void remove (const std :: list <CT> & r, std :: list <DIT> & out); - - void remove (DIT id, const std :: list <CT> & r, std :: list <CT> & out); - - void add (DIT id, const std :: list <CT> & l, std :: list <CT> & out); - - void add (CT client, const std :: list <DIT> & l, std :: list <DIT> & out); - -private: - std :: map < DIT, std :: list <CT> > mClientsPerDataItemMap; + inline LocUnorderedSetMap() {} + inline LocUnorderedSetMap(size_t size) : mMap(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>(0); + } + + // This gets all the KEYs from the map + inline unordered_set<KEY> getKeys() { + unordered_set<KEY> keys(0); + 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(0); + + if (newVals.empty()) { + mMap.erase(key); + } else { + auto curVals = mMap[key]; + mMap[key] = newVals; + goneVals = removeAndReturnInterset(curVals, newVals); + } + return goneVals; + } }; -} // namespace loc_core +} // namespace loc_util -#endif // #ifndef __DATAITEMINDEX_H__ +#endif // #ifndef __LOC_UNORDERDED_SETMAP_H__ |