changed SystemStatusOsObserver

to allow clients to subscribe before subscription obj
arrives, and also simplified ClientIndex and DataItemIndex
implementation significantly.

Change-Id: I092f344e688fa698aa98795b8a8f0c1ba8fcd9e4
CRs-Fixed: 2218519
This commit is contained in:
Kevin Tang 2018-03-23 22:57:51 -07:00
parent 86e1b52c81
commit 36da980fea
13 changed files with 473 additions and 1154 deletions

View file

@ -30,9 +30,6 @@ LOCAL_SRC_FILES += \
LocDualContext.cpp \ LocDualContext.cpp \
loc_core_log.cpp \ loc_core_log.cpp \
data-items/DataItemsFactoryProxy.cpp \ data-items/DataItemsFactoryProxy.cpp \
data-items/common/ClientIndex.cpp \
data-items/common/DataItemIndex.cpp \
data-items/common/IndexFactory.cpp \
SystemStatusOsObserver.cpp \ SystemStatusOsObserver.cpp \
SystemStatus.cpp SystemStatus.cpp

View file

@ -38,9 +38,6 @@ libloc_core_la_c_sources = \
LocDualContext.cpp \ LocDualContext.cpp \
loc_core_log.cpp \ loc_core_log.cpp \
data-items/DataItemsFactoryProxy.cpp \ data-items/DataItemsFactoryProxy.cpp \
data-items/common/ClientIndex.cpp \
data-items/common/DataItemIndex.cpp \
data-items/common/IndexFactory.cpp \
SystemStatusOsObserver.cpp \ SystemStatusOsObserver.cpp \
SystemStatus.cpp SystemStatus.cpp

View file

@ -1694,9 +1694,7 @@ bool SystemStatus::eventConnectionStatus(bool connected, int8_t type)
// send networkinof dataitem to systemstatus observer clients // send networkinof dataitem to systemstatus observer clients
SystemStatusNetworkInfo s(type, "", "", false, connected, false); SystemStatusNetworkInfo s(type, "", "", false, connected, false);
list<IDataItemCore*> dl(0); mSysStatusObsvr.notify({&s});
dl.push_back(&s);
mSysStatusObsvr.notify(dl);
} }
return true; return true;
} }

View file

@ -32,28 +32,20 @@
#include <SystemStatus.h> #include <SystemStatus.h>
#include <SystemStatusOsObserver.h> #include <SystemStatusOsObserver.h>
#include <IDataItemCore.h> #include <IDataItemCore.h>
#include <IClientIndex.h>
#include <IDataItemIndex.h>
#include <IndexFactory.h>
#include <DataItemsFactoryProxy.h> #include <DataItemsFactoryProxy.h>
namespace loc_core namespace loc_core
{ {
SystemStatusOsObserver::SystemStatusOsObserver( template <typename CINT, typename COUT>
SystemStatus* systemstatus, const MsgTask* msgTask) : COUT SystemStatusOsObserver::containerTransfer(CINT& inContainer) {
mSystemStatus(systemstatus), COUT outContainer(0);
mAddress("SystemStatusOsObserver"), for (auto item : inContainer) {
#ifdef USE_GLIB outContainer.insert(outContainer.begin(), item);
mBackHaulConnectReqCount(0), }
#endif return outContainer;
mClientIndex(IndexFactory<IDataItemObserver*, DataItemId> :: createClientIndex()),
mDataItemIndex(IndexFactory<IDataItemObserver*, DataItemId> :: createDataItemIndex())
{
mContext.mMsgTask = msgTask;
} }
SystemStatusOsObserver::~SystemStatusOsObserver() SystemStatusOsObserver::~SystemStatusOsObserver() {
{
// Close data-item library handle // Close data-item library handle
DataItemsFactoryProxy::closeDataItemLibraryHandle(); DataItemsFactoryProxy::closeDataItemLibraryHandle();
@ -65,290 +57,238 @@ SystemStatusOsObserver::~SystemStatusOsObserver()
} }
mDataItemCache.clear(); mDataItemCache.clear();
delete mClientIndex;
delete mDataItemIndex;
} }
void SystemStatusOsObserver::setSubscriptionObj(IDataItemSubscription* subscriptionObj) void SystemStatusOsObserver::setSubscriptionObj(IDataItemSubscription* subscriptionObj)
{ {
mContext.mSubscriptionObj = subscriptionObj; struct SetSubsObj : public LocMsg {
ObserverContext& mContext;
IDataItemSubscription* mSubsObj;
inline SetSubsObj(ObserverContext& context, IDataItemSubscription* subscriptionObj) :
mContext(context), mSubsObj(subscriptionObj) {}
void proc() const {
mContext.mSubscriptionObj = mSubsObj;
LOC_LOGD("Request cache size - Subscribe:%zu RequestData:%zu", if (!mContext.mSSObserver->mDataItemToClients.empty()) {
mSubscribeReqCache.size(), mReqDataCache.size()); list<DataItemId> dis(
containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
// we have received the subscription object. process cached requests mContext.mSSObserver->mDataItemToClients.getKeys()));
// process - subscribe request cache mContext.mSubscriptionObj->subscribe(dis, mContext.mSSObserver);
for (auto each : mSubscribeReqCache) { mContext.mSubscriptionObj->requestData(dis, mContext.mSSObserver);
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();
} }
} };
else {
// not found if (nullptr == subscriptionObj) {
reqCache[client] = l; LOC_LOGw("subscriptionObj is NULL");
} else {
mContext.mMsgTask->sendMsg(new SetSubsObj(mContext, subscriptionObj));
} }
} }
/****************************************************************************** /******************************************************************************
IDataItemSubscription Overrides IDataItemSubscription Overrides
******************************************************************************/ ******************************************************************************/
void SystemStatusOsObserver::subscribe( void SystemStatusOsObserver::subscribe(const list<DataItemId>& l, IDataItemObserver* client,
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 { struct HandleSubscribeReq : public LocMsg {
HandleSubscribeReq(SystemStatusOsObserver* parent, inline HandleSubscribeReq(SystemStatusOsObserver* parent,
const list<DataItemId>& l, IDataItemObserver* client) : list<DataItemId>& l, IDataItemObserver* client, bool requestData) :
mParent(parent), mClient(client), mDataItemList(l) {} mParent(parent), mClient(client),
virtual ~HandleSubscribeReq() {} mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)),
mToRequestData(requestData) {}
void proc() const { void proc() const {
unordered_set<DataItemId> dataItemsToSubscribe(0);
mParent->mDataItemToClients.add(mDataItemSet, {mClient}, &dataItemsToSubscribe);
mParent->mClientToDataItems.add(mClient, mDataItemSet);
if (mDataItemList.empty()) { mParent->sendCachedDataItems(mDataItemSet, mClient);
LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting");
return;
}
// Handle First Response // Send subscription set to framework
list<DataItemId> pendingFirstResponseList(0); if (nullptr != mParent->mContext.mSubscriptionObj && !dataItemsToSubscribe.empty()) {
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);
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"); 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; 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( void SystemStatusOsObserver::updateSubscription(
const list<DataItemId>& l, IDataItemObserver* client) 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 { struct HandleUpdateSubscriptionReq : public LocMsg {
HandleUpdateSubscriptionReq(SystemStatusOsObserver* parent, HandleUpdateSubscriptionReq(SystemStatusOsObserver* parent,
const list<DataItemId>& l, IDataItemObserver* client) : list<DataItemId>& l, IDataItemObserver* client) :
mParent(parent), mClient(client), mDataItemList(l) {} mParent(parent), mClient(client),
virtual ~HandleUpdateSubscriptionReq() {} mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)) {}
void proc() const { void proc() const {
if (mDataItemList.empty()) { unordered_set<DataItemId> dataItemsToSubscribe(0);
LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); unordered_set<DataItemId> dataItemsToUnsubscribe(0);
return; 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
list<DataItemId> currentlySubscribedList(0); // result, the entire entry will be removed. dataItemsToUnsubscribe will be
mParent->mClientIndex->getSubscribedList(mClient, currentlySubscribedList); // populated to keep the keys of the removed entries.
mParent->mDataItemToClients.trimOrRemove(
list<DataItemId> removeDataItemList(0); // this call updates <IDataItemObserver*, DataItemId> map; removes
set_difference(currentlySubscribedList.begin(), currentlySubscribedList.end(), // the DataItemId's that are not new to the clietn from mDataItemSet;
mDataItemList.begin(), mDataItemList.end(), // and returns a set of mDataItemSet's that are no longer used by client.
inserter(removeDataItemList,removeDataItemList.begin())); // This unused set of mDataItemSet's is passed to trimOrRemove method of
// <DataItemId, IDataItemObserver*> map to remove the client from the
// Handle First Response // corresponding entries, and gets a set of the entries that are
list<DataItemId> pendingFirstResponseList(0); // removed from the <DataItemId, IDataItemObserver*> map as a result.
mParent->mClientIndex->add(mClient, mDataItemList, pendingFirstResponseList); 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 // Send First Response
mParent->sendFirstResponse(pendingFirstResponseList, mClient); mParent->sendCachedDataItems(mDataItemSet, mClient);
list<DataItemId> yetToSubscribeDataItemsList(0); if (nullptr != mParent->mContext.mSubscriptionObj) {
mParent->mDataItemIndex->add( // Send subscription set to framework
mClient, mDataItemList, yetToSubscribeDataItemsList); if (!dataItemsToSubscribe.empty()) {
LOC_LOGD("Subscribe Request sent to framework for the following");
mParent->logMe(dataItemsToSubscribe);
// Send subscription list to framework mParent->mContext.mSubscriptionObj->subscribe(
if (!yetToSubscribeDataItemsList.empty()) { containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
mParent->mContext.mSubscriptionObj->subscribe( std::move(dataItemsToSubscribe)),
yetToSubscribeDataItemsList, mParent); 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);
if (!mParent->mClientIndex->isSubscribedClient(mClient)) {
mParent->mDataItemIndex->remove(
list<IDataItemObserver*> (1,mClient), unsubscribeList);
}
if (!unsubscribeList.empty()) {
// Send unsubscribe to framework // Send unsubscribe to framework
mParent->mContext.mSubscriptionObj->unsubscribe(unsubscribeList, mParent); if (!dataItemsToUnsubscribe.empty()) {
LOC_LOGD("Unsubscribe Request sent to framework for the following"); LOC_LOGD("Unsubscribe Request sent to framework for the following");
mParent->logMe(unsubscribeList); mParent->logMe(dataItemsToUnsubscribe);
mParent->mContext.mSubscriptionObj->unsubscribe(
containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
std::move(dataItemsToUnsubscribe)),
mParent);
}
} }
} }
SystemStatusOsObserver* mParent; SystemStatusOsObserver* mParent;
IDataItemObserver* mClient; IDataItemObserver* mClient;
const list<DataItemId> mDataItemList; unordered_set<DataItemId> mDataItemSet;
}; };
mContext.mMsgTask->sendMsg(new (nothrow) HandleUpdateSubscriptionReq(this, l, client));
}
void SystemStatusOsObserver::requestData( if (l.empty() || nullptr == client) {
const list<DataItemId>& l, IDataItemObserver* client) LOC_LOGw("Data item set is empty or client is nullptr");
{ } else {
if (nullptr == mContext.mSubscriptionObj) { mContext.mMsgTask->sendMsg(
LOC_LOGD("%s]: Subscription object is NULL. Caching requests", __func__); new HandleUpdateSubscriptionReq(this, (list<DataItemId>&)l, client));
cacheObserverRequest(mReqDataCache, l, client);
return;
} }
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( void SystemStatusOsObserver::unsubscribe(
const list<DataItemId>& l, IDataItemObserver* client) 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 { struct HandleUnsubscribeReq : public LocMsg {
HandleUnsubscribeReq(SystemStatusOsObserver* parent, HandleUnsubscribeReq(SystemStatusOsObserver* parent,
const list<DataItemId>& l, IDataItemObserver* client) : list<DataItemId>& l, IDataItemObserver* client) :
mParent(parent), mClient(client), mDataItemList(l) {} mParent(parent), mClient(client),
virtual ~HandleUnsubscribeReq() {} mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)) {}
void proc() const { void proc() const {
if (mDataItemList.empty()) { unordered_set<DataItemId> dataItemsUnusedByClient(0);
LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); unordered_set<IDataItemObserver*> clientToRemove(0);
return; mParent->mClientToDataItems.trimOrRemove({mClient}, mDataItemSet, &clientToRemove,
} &dataItemsUnusedByClient);
unordered_set<DataItemId> dataItemsToUnsubscribe(0);
mParent->mDataItemToClients.trimOrRemove(dataItemsUnusedByClient, {mClient},
&dataItemsToUnsubscribe, nullptr);
list<DataItemId> unsubscribeList(0); if (nullptr != mParent->mContext.mSubscriptionObj && !dataItemsToUnsubscribe.empty()) {
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);
}
}
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"); LOC_LOGD("Unsubscribe Request sent to framework for the following data items");
mParent->logMe(unsubscribeList); mParent->logMe(dataItemsToUnsubscribe);
// Send unsubscribe to framework
mParent->mContext.mSubscriptionObj->unsubscribe(
containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
std::move(dataItemsToUnsubscribe)),
mParent);
} }
} }
SystemStatusOsObserver* mParent; SystemStatusOsObserver* mParent;
IDataItemObserver* mClient; 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) void SystemStatusOsObserver::unsubscribeAll(IDataItemObserver* client)
{ {
if (nullptr == mContext.mSubscriptionObj) {
LOC_LOGE("%s:%d]: Subscription object is NULL", __func__, __LINE__);
return;
}
struct HandleUnsubscribeAllReq : public LocMsg { struct HandleUnsubscribeAllReq : public LocMsg {
HandleUnsubscribeAllReq(SystemStatusOsObserver* parent, HandleUnsubscribeAllReq(SystemStatusOsObserver* parent,
IDataItemObserver* client) : IDataItemObserver* client) :
mParent(parent), mClient(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()) { void proc() const {
// Send unsubscribe to framework unordered_set<DataItemId> diByClient = mParent->mClientToDataItems.getValSet(mClient);
mParent->mContext.mSubscriptionObj->unsubscribe(unsubscribeList, mParent); if (!diByClient.empty()) {
LOC_LOGD("Unsubscribe Request sent to framework for the following data items"); unordered_set<DataItemId> dataItemsToUnsubscribe;
mParent->logMe(unsubscribeList); 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; SystemStatusOsObserver* mParent;
IDataItemObserver* mClient; 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) 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 { struct HandleNotify : public LocMsg {
HandleNotify(SystemStatusOsObserver* parent, const list<IDataItemCore*>& l) : HandleNotify(SystemStatusOsObserver* parent, vector<IDataItemCore*>& v) :
mParent(parent), mDList(l) {} mParent(parent), mDiVec(std::move(v)) {}
virtual ~HandleNotify() {
for (auto each : mDList) { inline virtual ~HandleNotify() {
delete each; for (auto item : mDiVec) {
delete item;
} }
} }
void proc() const { void proc() const {
// Update Cache with received data items and prepare // Update Cache with received data items and prepare
// list of data items to be sent. // list of data items to be sent.
list<DataItemId> dataItemIdsToBeSent(0); unordered_set<DataItemId> dataItemIdsToBeSent(0);
for (auto item : mDList) { for (auto item : mDiVec) {
bool dataItemUpdated = false; if (mParent->updateCache(item)) {
mParent->updateCache(item, dataItemUpdated); dataItemIdsToBeSent.insert(item->getId());
if (dataItemUpdated) {
dataItemIdsToBeSent.push_back(item->getId());
} }
} }
// Send data item to all subscribed clients // Send data item to all subscribed clients
list<IDataItemObserver*> clientList(0); unordered_set<IDataItemObserver*> clientSet(0);
for (auto each : dataItemIdsToBeSent) { for (auto each : dataItemIdsToBeSent) {
list<IDataItemObserver*> clients(0); auto clients = mParent->mDataItemToClients.getValSetPtr(each);
mParent->mDataItemIndex->getListOfSubscribedClients(each, clients); if (nullptr != clients) {
for (auto each_cient: clients) { clientSet.insert(clients->begin(), clients->end());
clientList.push_back(each_cient);
} }
} }
clientList.unique();
for (auto client : clientList) { for (auto client : clientSet) {
list<DataItemId> dataItemIdsSubscribedByThisClient(0); unordered_set<DataItemId> dataItemIdsForThisClient(
list<DataItemId> dataItemIdsToBeSentForThisClient(0); mParent->mClientToDataItems.getValSet(client));
mParent->mClientIndex->getSubscribedList( for (auto id : dataItemIdsForThisClient) {
client, dataItemIdsSubscribedByThisClient); if (dataItemIdsToBeSent.find(id) == dataItemIdsToBeSent.end()) {
dataItemIdsSubscribedByThisClient.sort(); dataItemIdsForThisClient.erase(id);
dataItemIdsToBeSent.sort(); }
}
set_intersection(dataItemIdsToBeSent.begin(), mParent->sendCachedDataItems(dataItemIdsForThisClient, client);
dataItemIdsToBeSent.end(),
dataItemIdsSubscribedByThisClient.begin(),
dataItemIdsSubscribedByThisClient.end(),
inserter(dataItemIdsToBeSentForThisClient,
dataItemIdsToBeSentForThisClient.begin()));
mParent->sendCachedDataItems(dataItemIdsToBeSentForThisClient, client);
dataItemIdsSubscribedByThisClient.clear();
dataItemIdsToBeSentForThisClient.clear();
} }
} }
SystemStatusOsObserver* mParent; 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 // 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()) { if (citer == mActiveRequestCount.end()) {
// Data item not found in map // Data item not found in map
// Add reference count as 1 and add dataitem to 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 // 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()) { if (citer != mActiveRequestCount.end()) {
// found // found
citer->second--; citer->second--;
@ -573,84 +507,65 @@ bool SystemStatusOsObserver::disconnectBackhaul()
/****************************************************************************** /******************************************************************************
Helpers Helpers
******************************************************************************/ ******************************************************************************/
void SystemStatusOsObserver::sendFirstResponse(
const list<DataItemId>& l, 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 (dataItems.empty()) {
LOC_LOGV("No items to notify. Nothing to do. Exiting");
return;
}
to->notify(dataItems);
}
void SystemStatusOsObserver::sendCachedDataItems( void SystemStatusOsObserver::sendCachedDataItems(
const list<DataItemId>& l, IDataItemObserver* to) const unordered_set<DataItemId>& s, IDataItemObserver* to)
{ {
string clientName; if (nullptr == to) {
to->getName(clientName); LOC_LOGv("client pointer is NULL.");
list<IDataItemCore*> dataItems(0); } else {
string clientName;
to->getName(clientName);
list<IDataItemCore*> dataItems(0);
for (auto each : l) { for (auto each : s) {
string dv; auto citer = mDataItemCache.find(each);
IDataItemCore* di = mDataItemCache[each]; if (citer != mDataItemCache.end()) {
di->stringify(dv); string dv;
LOC_LOGI("DataItem: %s >> %s", dv.c_str(), clientName.c_str()); citer->second->stringify(dv);
dataItems.push_back(di); 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.");
} else {
to->notify(dataItems);
}
} }
to->notify(dataItems);
} }
void SystemStatusOsObserver::updateCache(IDataItemCore* d, bool& dataItemUpdated) bool SystemStatusOsObserver::updateCache(IDataItemCore* d)
{ {
if (nullptr == d) { bool dataItemUpdated = false;
return;
}
// Check if data item exists in cache // Request systemstatus to record this dataitem in its cache
map<DataItemId, IDataItemCore*>::iterator citer = // if the return is false, it means that SystemStatus is not
mDataItemCache.find(d->getId()); // handling it, so SystemStatusOsObserver also doesn't.
if (citer == mDataItemCache.end()) { // So it has to be true to proceed.
// New data item; not found in cache if (nullptr != d && mSystemStatus->eventDataItemNotify(d)) {
IDataItemCore* dataitem = DataItemsFactoryProxy::createNewDataItem(d->getId()); auto citer = mDataItemCache.find(d->getId());
if (nullptr == dataitem) { if (citer == mDataItemCache.end()) {
return; // 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 if (dataItemUpdated) {
dataitem->copy(d); LOC_LOGV("DataItem:%d updated:%d", d->getId(), dataItemUpdated);
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) { return dataItemUpdated;
LOC_LOGV("DataItem:%d updated:%d", d->getId(), dataItemUpdated);
}
} }
} // namespace loc_core } // namespace loc_core

View file

@ -41,6 +41,7 @@
#include <IOsObserver.h> #include <IOsObserver.h>
#include <loc_pla.h> #include <loc_pla.h>
#include <log_util.h> #include <log_util.h>
#include <LocUnorderedSetMap.h>
namespace loc_core namespace loc_core
{ {
@ -48,39 +49,57 @@ namespace loc_core
SystemStatusOsObserver SystemStatusOsObserver
******************************************************************************/ ******************************************************************************/
using namespace std; using namespace std;
using namespace loc_util;
// Forward Declarations // Forward Declarations
class IDataItemCore; class IDataItemCore;
template<typename CT, typename DIT> class IClientIndex; class SystemStatus;
template<typename CT, typename DIT> class IDataItemIndex; 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; IDataItemSubscription* mSubscriptionObj;
IFrameworkActionReq* mFrameworkActionReqObj; IFrameworkActionReq* mFrameworkActionReqObj;
const MsgTask* mMsgTask; const MsgTask* mMsgTask;
SystemStatusOsObserver* mSSObserver;
inline SystemContext() : inline ObserverContext(const MsgTask* msgTask, SystemStatusOsObserver* observer) :
mSubscriptionObj(NULL), mSubscriptionObj(NULL), mFrameworkActionReqObj(NULL),
mFrameworkActionReqObj(NULL), mMsgTask(msgTask), mSSObserver(observer) {}
mMsgTask(NULL) {}
}; };
typedef map<IDataItemObserver*, list<DataItemId>> ObserverReqCache;
// Clients wanting to get data from OS/Framework would need to // Clients wanting to get data from OS/Framework would need to
// subscribe with OSObserver using IDataItemSubscription interface. // subscribe with OSObserver using IDataItemSubscription interface.
// Such clients would need to implement IDataItemObserver interface // Such clients would need to implement IDataItemObserver interface
// to receive data when it becomes available. // to receive data when it becomes available.
class SystemStatus;
class SystemStatusOsObserver : public IOsObserver { class SystemStatusOsObserver : public IOsObserver {
public: public:
// ctor // ctor
SystemStatusOsObserver( inline SystemStatusOsObserver(SystemStatus* systemstatus, const MsgTask* msgTask) :
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 // dtor
~SystemStatusOsObserver(); ~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 // To set the subscription object
virtual void setSubscriptionObj(IDataItemSubscription* subscriptionObj); virtual void setSubscriptionObj(IDataItemSubscription* subscriptionObj);
@ -96,38 +115,40 @@ public:
} }
// IDataItemSubscription Overrides // IDataItemSubscription Overrides
virtual void subscribe(const list<DataItemId>& l, IDataItemObserver* client); inline virtual void subscribe(const list<DataItemId>& l, IDataItemObserver* client) override {
virtual void updateSubscription(const list<DataItemId>& l, IDataItemObserver* client); subscribe(l, client, false);
virtual void requestData(const list<DataItemId>& l, IDataItemObserver* client); }
virtual void unsubscribe(const list<DataItemId>& l, IDataItemObserver* client); virtual void updateSubscription(const list<DataItemId>& l, IDataItemObserver* client) override;
virtual void unsubscribeAll(IDataItemObserver* client); 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 // IDataItemObserver Overrides
virtual void notify(const list<IDataItemCore*>& dlist); virtual void notify(const list<IDataItemCore*>& dlist) override;
inline virtual void getName(string& name) { inline virtual void getName(string& name) override {
name = mAddress; name = mAddress;
} }
// IFrameworkActionReq Overrides // IFrameworkActionReq Overrides
virtual void turnOn(DataItemId dit, int timeOut = 0); virtual void turnOn(DataItemId dit, int timeOut = 0) override;
virtual void turnOff(DataItemId dit); virtual void turnOff(DataItemId dit) override;
#ifdef USE_GLIB #ifdef USE_GLIB
virtual bool connectBackhaul(); virtual bool connectBackhaul() override;
virtual bool disconnectBackhaul(); virtual bool disconnectBackhaul();
#endif #endif
private: private:
SystemStatus* mSystemStatus; SystemStatus* mSystemStatus;
SystemContext mContext; ObserverContext mContext;
const string mAddress; const string mAddress;
IClientIndex<IDataItemObserver*, DataItemId>* mClientIndex; ClientToDataItems mClientToDataItems;
IDataItemIndex<IDataItemObserver*, DataItemId>* mDataItemIndex; DataItemToClients mDataItemToClients;
map<DataItemId, IDataItemCore*> mDataItemCache; DataItemIdToCore mDataItemCache;
map<DataItemId, int> mActiveRequestCount; DataItemIdToInt mActiveRequestCount;
// Cache the subscribe and requestData till subscription obj is obtained // Cache the subscribe and requestData till subscription obj is obtained
ObserverReqCache mSubscribeReqCache;
ObserverReqCache mReqDataCache;
void cacheObserverRequest(ObserverReqCache& reqCache, void cacheObserverRequest(ObserverReqCache& reqCache,
const list<DataItemId>& l, IDataItemObserver* client); const list<DataItemId>& l, IDataItemObserver* client);
#ifdef USE_GLIB #ifdef USE_GLIB
@ -135,13 +156,16 @@ private:
int mBackHaulConnectReqCount; int mBackHaulConnectReqCount;
#endif #endif
void subscribe(const list<DataItemId>& l, IDataItemObserver* client, bool toRequestData);
// Helpers // Helpers
void sendFirstResponse(const list<DataItemId>& l, IDataItemObserver* to); void sendCachedDataItems(const unordered_set<DataItemId>& s, IDataItemObserver* to);
void sendCachedDataItems(const list<DataItemId>& l, IDataItemObserver* to); bool updateCache(IDataItemCore* d);
void updateCache(IDataItemCore* d, bool& dataItemUpdated); inline void logMe(const unordered_set<DataItemId>& l) {
inline void logMe(const list<DataItemId>& l) { IF_LOC_LOGD {
for (auto id : l) { for (auto id : l) {
LOC_LOGD("DataItem %d", id); LOC_LOGD("DataItem %d", id);
}
} }
} }
}; };

View file

@ -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>;
}

View file

@ -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>;
}

View file

@ -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__

View file

@ -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__

View file

@ -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>;
}

View file

@ -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__

View file

@ -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__

View file

@ -26,45 +26,167 @@
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
*/ */
#ifndef __LOC_UNORDERDED_SETMAP_H__
#define __LOC_UNORDERDED_SETMAP_H__
#ifndef __DATAITEMINDEX_H__ #include <algorithm>
#define __DATAITEMINDEX_H__ #include <unordered_set>
#include <unordered_map>
#include <list> using std::unordered_set;
#include <map> using std::unordered_map;
#include <IDataItemIndex.h>
using loc_core::IDataItemIndex; namespace loc_util {
namespace loc_core // 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);
}
}
}
template <typename CT, typename DIT> // 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;
}
class DataItemIndex : public IDataItemIndex <CT, DIT> { 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: public:
inline LocUnorderedSetMap() {}
inline LocUnorderedSetMap(size_t size) : mMap(size) {}
DataItemIndex (); inline bool empty() { return mMap.empty(); }
~DataItemIndex (); // 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;
}
void getListOfSubscribedClients (DIT id, std :: list <CT> & out); // 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);
}
int remove (DIT id); // 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;
}
void remove (const std :: list <CT> & r, std :: list <DIT> & out); inline bool remove(const KEY& key) {
return mMap.erase(key) > 0;
}
void remove (DIT id, const std :: list <CT> & r, std :: list <CT> & out); // 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);
}
}
}
void add (DIT id, const std :: list <CT> & l, std :: list <CT> & out); // 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;
}
void add (CT client, const std :: list <DIT> & l, std :: list <DIT> & out); // 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);
}
}
}
private: // This puts *newVals* into the map keyed by *key*, and returns the VALs that are
std :: map < DIT, std :: list <CT> > mClientsPerDataItemMap; // 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__