home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-09-17 | 21.8 KB | 652 lines | [TEXT/MPS ] |
- //========================================================================================
- //
- // File: FWIntSpc.cpp
- // Release Version: $ ODF 2 $
- //
- // Copyright: (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
- //
- //========================================================================================
-
- #ifndef FWINTSPC_H
- #include "FWIntSpc.h"
- #endif
-
- #ifndef FWNOTIFR_H
- #include "FWNotifr.h"
- #endif
-
- #ifndef FWNOTIFN_H
- #include "FWNotifn.h"
- #endif
-
- //========================================================================================
- // Template Instantiations
- //========================================================================================
-
- FW_DEFINE_AUTO_TEMPLATE(FW_TOrderedCollection, FW_PrivInterestTag)
- FW_DEFINE_AUTO_TEMPLATE(FW_TOrderedCollection, FW_SPrivTaggableInterest)
- FW_DEFINE_AUTO_TEMPLATE(FW_TOrderedCollectionIterator, FW_SPrivTaggableInterest)
-
- #ifdef FW_USE_TEMPLATE_PRAGMAS
-
- #pragma template_access public
-
- #pragma template FW_TOrderedCollection<FW_SPrivTaggableInterest>
- #pragma template FW_TOrderedCollectionIterator<FW_SPrivTaggableInterest>
- #pragma template FW_TMap<FW_ObjectID, FW_SPrivNotifierEntry>
- #pragma template FW_TPair<FW_ObjectID, FW_SPrivNotifierEntry>
- #pragma template FW_TMap<FW_ObjectID, FW_SPrivReceiverEntry>
- #pragma template FW_TPair<FW_ObjectID, FW_SPrivReceiverEntry>
- #pragma template FW_TPrivDestroyer<FW_CPrivInterestSpace>
-
- #else
-
- template class FW_TOrderedCollection<FW_SPrivTaggableInterest>;
- template class FW_TOrderedCollectionIterator<FW_SPrivTaggableInterest>;
- template class FW_TMap<FW_ObjectID, FW_SPrivNotifierEntry>;
- template class FW_TPair<FW_ObjectID, FW_SPrivNotifierEntry>;
- template class FW_TMap<FW_ObjectID, FW_SPrivReceiverEntry>;
- template class FW_TPair<FW_ObjectID, FW_SPrivReceiverEntry>;
- template class FW_TPrivDestroyer<FW_CPrivInterestSpace>;
-
- #endif
-
- //========================================================================================
- // Static Allocations
- //========================================================================================
-
- FW_CPrivInterestSpace* FW_CPrivInterestSpace::fgInstance;
- FW_TPrivDestroyer<FW_CPrivInterestSpace> FW_CPrivInterestSpace::fgDestroyer;
-
- //========================================================================================
- // Static Comparison Callbacks
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // FW_CompareNotifierEntries
- //----------------------------------------------------------------------------------------
-
- static int FW_CompareNotifierEntries(void* first, void* second)
- {
- return (((FW_CPrivNotifierInterestPair*)first)->fKey - ((FW_CPrivNotifierInterestPair*)second)->fKey);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_NotifierEntryMatchProc
- //----------------------------------------------------------------------------------------
-
- static FW_Boolean FW_NotifierEntryMatchProc(const void* v1, const void* v2)
- {
- const FW_SPrivTaggableInterest* value1 = (FW_SPrivTaggableInterest*)v1;
- const FW_SPrivTaggableInterest* value2 = (FW_SPrivTaggableInterest*)v2;
-
- // compare receiver and message...don't compare fMarked
- return ((value1->fReceiver == value2->fReceiver) && (value1->fMessage == value2->fMessage));
- }
-
- //----------------------------------------------------------------------------------------
- // FW_ReceiverEntryMatchProc
- //----------------------------------------------------------------------------------------
-
- static FW_Boolean FW_ReceiverEntryMatchProc(const void* v1, const void* v2)
- {
- return ((*(FW_CInterest*)v1) == (*(FW_CInterest*)v2));
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CompareReceiverEntries
- //----------------------------------------------------------------------------------------
-
- static int FW_CompareReceiverEntries(void* first, void* second)
- {
- FW_ObjectID firstID = ((FW_CPrivReceiverInterestPair*)first)->fKey;
- FW_ObjectID secondID = ((FW_CPrivReceiverInterestPair*)second)->fKey;
-
- return (((FW_CPrivReceiverInterestPair*)first)->fKey - ((FW_CPrivReceiverInterestPair*)second)->fKey);
- }
-
- //========================================================================================
- // class FW_CPrivInterestSpace
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::FW_CPrivInterestSpace
- //----------------------------------------------------------------------------------------
-
- FW_CPrivInterestSpace::FW_CPrivInterestSpace() :
- fLastNotifierID(0),
- fLastReceiverID(0),
- fLastTag(0),
- fNotifierInterestMap(FW_CompareNotifierEntries),
- fReceiverInterestMap(FW_CompareReceiverEntries)
- {
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::~FW_CPrivInterestSpace
- //----------------------------------------------------------------------------------------
-
- FW_CPrivInterestSpace::~FW_CPrivInterestSpace()
- {
- fgInstance = NULL;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::Instance
- //----------------------------------------------------------------------------------------
-
- FW_CPrivInterestSpace* FW_CPrivInterestSpace::Instance()
- {
- if (!fgInstance)
- {
- fgInstance = new FW_CPrivInterestSpace;
- fgDestroyer.SetDoomed(fgInstance);
- }
- return fgInstance;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::AddNotifierInterest
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivInterestSpace::AddNotifierInterest(FW_MReceiver* receiver,
- const FW_CInterest& interest)
- {
- FW_ASSERT(receiver->IsConnected());
-
- FW_MNotifier* notifier = interest.GetNotifier();
- FW_ObjectID notifierID = notifier->PrivGetNotifierID();
- FW_CPrivNotifierInterestPair* pair;
-
- if (notifierID == 0)
- {
- FW_SPrivNotifierEntry entry;
-
- notifierID = GetNextNotifierID();
- notifier->PrivSetNotifierID(notifierID);
-
- entry.fNotifier = notifier;
- entry.fTaggedInterestList = FW_NEW(FW_CPrivTaggableInterestList, (FW_NotifierEntryMatchProc));
-
- pair = fNotifierInterestMap.Add(notifierID, entry);
- }
- else
- pair = fNotifierInterestMap.Find(notifierID);
-
- FW_ASSERT(pair);
-
- FW_CPrivTaggableInterestList* interestList = pair->fValue.fTaggedInterestList;
-
- FW_SPrivTaggableInterest* entry = new FW_SPrivTaggableInterest;
- entry->fReceiver = receiver;
- entry->fMessage = interest.GetMessage();
- entry->fTags[0] = entry->fTags[1] = 0;
- entry->fTagCollection = NULL;
-
- if (interestList->Contains(entry))
- {
- FW_DEBUG_MESSAGE("FW_CPrivInterestSpace::AddNotifierInterest - Trying to add an interest that already exists");
- delete entry;
- return;
- }
-
- interestList->AddLast(entry);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::AddReceiverInterest
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivInterestSpace::AddReceiverInterest(FW_MReceiver* receiver,
- const FW_CInterest& interest)
- {
- FW_ObjectID receiverID = receiver->PrivGetReceiverID();
- FW_CPrivReceiverInterestPair* receiverPair;
-
- if (receiverID == 0)
- {
- FW_SPrivReceiverEntry entry;
-
- receiverID = GetNextReceiverID();
- receiver->PrivSetReceiverID(receiverID);
-
- entry.fReceiver = receiver;
- entry.fInterestList = FW_NEW(FW_CInterestCollection, (FW_ReceiverEntryMatchProc));
-
- receiverPair = fReceiverInterestMap.Add(receiverID, entry);
- }
- else
- receiverPair = fReceiverInterestMap.Find(receiverID);
-
- FW_ASSERT(receiverPair);
-
- FW_CInterestCollection* interestList = receiverPair->fValue.fInterestList;
-
- if (interestList->Contains(&interest))
- {
- FW_DEBUG_MESSAGE("FW_CPrivInterestSpace::AddReceiverInterest - Trying to add an interest that already exists");
- return;
- }
-
- FW_CInterest* interestCopy = new FW_CInterest(interest);
- interestList->AddLast(interestCopy);
-
- if (receiver->IsConnected())
- AddNotifierInterest(receiver, interest);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::RemoveNotifierInterest
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivInterestSpace::RemoveNotifierInterest(FW_MReceiver* receiver, const FW_CInterest& interest)
- {
- FW_MNotifier* notifier = interest.GetNotifier();
- FW_ObjectID notifierID = notifier->PrivGetNotifierID();
-
- FW_ASSERT(notifierID != 0); // if this is false, the interest can't be registered
-
- FW_CPrivNotifierInterestPair* pair = fNotifierInterestMap.Find(notifierID);
- if (pair && (pair->fValue.fNotifier == notifier))
- {
- FW_Message message = interest.GetMessage();
- FW_CPrivTaggableInterestList* interestList = pair->fValue.fTaggedInterestList;
- FW_SPrivTaggableInterest* currentInterest = NULL;
- FW_SPrivTaggableInterest* sentinel = NULL;
- FW_Boolean done = false;
-
- // there should only be one instance of the specified interest, but we
- // take a conservative approach and walk the entire interest list
- while (!done)
- {
- currentInterest = sentinel ? interestList->After(sentinel) : interestList->First();
-
- if (currentInterest == NULL)
- done = true;
- else
- {
- if ((currentInterest->fReceiver == receiver) && (currentInterest->fMessage == message))
- {
- interestList->Remove(currentInterest);
- delete currentInterest->fTagCollection;
- delete(currentInterest);
- }
- else
- sentinel = currentInterest;
- }
- }
-
- if (interestList->Count() == 0)
- {
- delete interestList;
- fNotifierInterestMap.Remove(notifierID);
- notifier->PrivSetNotifierID(0);
- }
- }
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::RemoveReceiverInterest
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivInterestSpace::RemoveReceiverInterest(FW_MReceiver* receiver,
- const FW_CInterest& interest,
- FW_Boolean removeNotifierInterest)
- {
- FW_ObjectID receiverID = receiver->PrivGetReceiverID();
- FW_ASSERT(receiverID != 0);
- FW_CPrivReceiverInterestPair* pair = fReceiverInterestMap.Find(receiverID);
-
- if (pair && (pair->fValue.fReceiver == receiver))
- {
- FW_CInterest* entryToDelete = NULL;
- FW_CInterestCollection* interestList = pair->fValue.fInterestList;
- FW_CInterestCollectionIterator iter(interestList);
-
- for (FW_CInterest* curEntry = iter.First(); iter.IsNotComplete(); curEntry = iter.Next())
- {
- if (*curEntry == interest)
- {
- entryToDelete = curEntry;
- break;
- }
- }
-
- if (entryToDelete)
- {
- interestList->Remove(entryToDelete);
- delete entryToDelete;
-
- // only attempt to remove the notifier interest if the
- // receiver interest was found and removed. this handles
- // the case where a receiver cached a ptr to a notifier,
- // then the notifier was deleted, then receiver tried
- // to remove the interest using the cached ptr (which is
- // now dangling)
- if (removeNotifierInterest && receiver->IsConnected())
- RemoveNotifierInterest(receiver, interest);
- }
- }
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::HasInterest
- //----------------------------------------------------------------------------------------
-
- FW_Boolean FW_CPrivInterestSpace::HasInterest(const FW_MReceiver* receiver,
- const FW_CInterest& interest)
- {
- FW_Boolean result = false;
- FW_MNotifier* notifier = interest.GetNotifier();
- FW_ObjectID notifierID = notifier->PrivGetNotifierID();
- FW_Message message = interest.GetMessage();
-
- if (notifierID != 0)
- {
- FW_CPrivNotifierInterestPair* pair = fNotifierInterestMap.Find(notifierID);
- if (pair)
- {
- FW_TOrderedCollectionIterator<FW_SPrivTaggableInterest> iter(pair->fValue.fTaggedInterestList);
- for (FW_SPrivTaggableInterest* curEntry = iter.First();
- !result && iter.IsNotComplete();
- curEntry = iter.Next())
- {
- if ((curEntry->fReceiver == receiver) && (curEntry->fMessage == message))
- result = true;
- }
- }
- }
- return result;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::Notify
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivInterestSpace::Notify(Environment* ev,
- const FW_CNotification& notification)
- {
- FW_MNotifier* notifier = notification.GetNotifier();
- FW_ObjectID notifierID = notifier->PrivGetNotifierID();
-
- if (notifierID == 0) // notifier has no interests
- return;
-
- FW_Message message = notification.GetMessage();
-
- // only interests that are installed when notification begins get notified.
- // if additional interests are installed during notification, they will
- // not get notified. this is implemented by first iterating through
- // installed notifications, and marking them. we then conservatively
- // iterate through marked interests, until they are all satisfied.
- // this implementation allows interests to be deleted during notification.
-
- // the common case is for a notifier to have a single receiver interested
- // in a specific notification. when this case is detected, the receiver
- // is notified immediately, and the multiple iteration algorithm is not
- // used.
- FW_CPrivNotifierInterestPair* pair = fNotifierInterestMap.Find(notifierID);
- FW_ASSERT(pair);
- FW_ASSERT(notifier == pair->fValue.fNotifier);
-
- unsigned short interestsTagged;
- FW_SPrivTaggableInterest* interestEntry;
- FW_PrivInterestTag tag = GetNextTag();
-
- interestEntry = TagInterests(pair->fValue.fTaggedInterestList, message, tag, interestsTagged);
-
- // receivers needing notification are now marked. there are three possible states
- // at this point
- // a). no appropriate interests existed. this case is detected when foundMultiple
- // is false and interestEntry is NULL
- // b). a single eligible interest existed. this case is detected when foundMultiple
- // is false, and interestEntry is not NULL
- // c). multiple eligible receivers were found. this case is detected when foundMultiple
- // is true
-
- if (interestsTagged == 1)
- {
- if (interestEntry)
- {
- // clear flag before notifying, in case entry is deleted as a result of notification
- FW_Boolean removed = RemoveTagFromInterest(interestEntry, tag);
- FW_ASSERT(removed);
- SendNotificationToReceiver(ev, interestEntry->fReceiver, notification);
- }
- }
- else
- {
- do
- {
- interestEntry = NULL;
- pair = fNotifierInterestMap.Find(notifierID);
- // validate that the notifier associated with the pair is, in fact, the
- // same notifier that initiated the notification. this virtually guaranteed
- // to be true because of the use of notifier IDs. the use of notifier id's
- // as keys is specifically to protect against the case where, as a consequence
- // of a notification, a notifier is deleted and, at the same time, a new
- // notifier is created at the same address. using object ids _and_ object
- // pointers prevents us from mistaking the new object's list for the old one.
- if (pair && (pair->fValue.fNotifier == notifier))
- {
- FW_TOrderedCollectionIterator<FW_SPrivTaggableInterest> iter(pair->fValue.fTaggedInterestList);
- for (FW_SPrivTaggableInterest* curEntry = iter.First(); iter.IsNotComplete(); curEntry = iter.Next())
- {
- if (RemoveTagFromInterest(curEntry, tag))
- {
- FW_ASSERT(curEntry->fMessage == message);
- interestEntry = curEntry;
- break;
- }
- }
- }
-
- if (interestEntry)
- SendNotificationToReceiver(ev, interestEntry->fReceiver, notification);
-
- } while (interestEntry);
- }
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::AddTagToInterest
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivInterestSpace::AddTagToInterest(FW_SPrivTaggableInterest* interest,
- FW_PrivInterestTag tag)
- {
- if (interest->fTags[0] == 0)
- interest->fTags[0] = tag;
- else if (interest->fTags[1] == 0)
- interest->fTags[1] = tag;
- else
- {
- if (!interest->fTagCollection)
- interest->fTagCollection = FW_NEW(FW_CPrivInterestTagCollection, ());
- interest->fTagCollection->AddLast((FW_PrivInterestTag*)tag);
-
- }
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::RemoveTagFromInterest
- //----------------------------------------------------------------------------------------
-
- FW_Boolean FW_CPrivInterestSpace::RemoveTagFromInterest(FW_SPrivTaggableInterest* interest,
- FW_PrivInterestTag tag)
- {
- FW_Boolean interestWasTagged = false;
- FW_PrivInterestTag* openSlot = NULL;
-
- if (interest->fTags[0] == tag)
- openSlot = &interest->fTags[0];
- else if (interest->fTags[1] == tag)
- openSlot = &interest->fTags[1];
-
- if (openSlot)
- {
- *openSlot = 0;
- interestWasTagged = true;
- }
-
- if (interest->fTagCollection)
- {
- FW_Boolean collectionShrunk = false;
- if (openSlot)
- {
- *openSlot = (FW_PrivInterestTag)interest->fTagCollection->RemoveLast();
- collectionShrunk = true;
- }
- else if (interest->fTagCollection->Contains((FW_PrivInterestTag*)tag))
- {
- interest->fTagCollection->Remove((FW_PrivInterestTag*)tag);
- interestWasTagged = true;
- collectionShrunk = true;
- }
-
- if (collectionShrunk && (interest->fTagCollection->Count() == 0))
- {
- delete interest->fTagCollection;
- interest->fTagCollection = NULL;
- }
- }
-
- return interestWasTagged;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::TagInterests
- //----------------------------------------------------------------------------------------
-
- FW_SPrivTaggableInterest* FW_CPrivInterestSpace::TagInterests(FW_CPrivTaggableInterestList* interestList,
- FW_Message message,
- FW_PrivInterestTag tag,
- unsigned short& interestsTagged)
- {
- FW_SPrivTaggableInterest* firstTaggedInterest = NULL;
- interestsTagged = 0;
-
- FW_TOrderedCollectionIterator<FW_SPrivTaggableInterest> iter(interestList);
- for (FW_SPrivTaggableInterest* curEntry = iter.First(); iter.IsNotComplete(); curEntry = iter.Next())
- {
- if (curEntry->fMessage == message)
- {
- ++interestsTagged;
- if (!firstTaggedInterest)
- firstTaggedInterest = curEntry;
-
- AddTagToInterest(curEntry, tag);
- }
- }
-
- return firstTaggedInterest;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::SendNotificationToReceiver
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivInterestSpace::SendNotificationToReceiver(Environment* ev,
- FW_MReceiver* receiver,
- const FW_CNotification& notification)
- {
- FW_TRY
- {
- receiver->HandleNotification(ev, notification);
- }
- FW_CATCH_BEGIN
- FW_CATCH_EVERYTHING()
- {
- // swallow exceptions
- }
- FW_CATCH_END
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::RemoveReceiver
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivInterestSpace::RemoveReceiver(FW_MReceiver* receiver)
- {
- FW_ObjectID receiverID = receiver->PrivGetReceiverID();
- if (receiverID == 0)
- return;
-
- FW_CPrivReceiverInterestPair* pair = fReceiverInterestMap.Find(receiverID);
- FW_ASSERT(pair);
- FW_ASSERT(pair->fValue.fReceiver == receiver);
- FW_Boolean receiverIsConnected = receiver->IsConnected();
- FW_CInterestCollection* interestList = pair->fValue.fInterestList;
- FW_CInterest* lastEntry;
- do
- {
- lastEntry = interestList->RemoveLast();
- if (lastEntry)
- {
- if (receiverIsConnected)
- RemoveNotifierInterest(receiver, *lastEntry);
- delete lastEntry;
- }
- } while (lastEntry);
-
- delete interestList;
- fReceiverInterestMap.Remove(receiverID);
- receiver->PrivSetReceiverID(0);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::RemoveNotifier
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivInterestSpace::RemoveNotifier(FW_MNotifier* notifier)
- {
- FW_ObjectID notifierID = notifier->PrivGetNotifierID();
- if (notifierID == 0)
- return;
-
- FW_CPrivNotifierInterestPair* pair = fNotifierInterestMap.Find(notifierID);
- FW_ASSERT(pair);
- FW_ASSERT(notifier == pair->fValue.fNotifier);
- FW_ASSERT(pair->fValue.fTaggedInterestList);
-
- FW_CPrivTaggableInterestList* interestList = pair->fValue.fTaggedInterestList;
- FW_SPrivTaggableInterest* lastEntry;
- do
- {
- lastEntry = interestList->RemoveLast();
- if (lastEntry)
- {
- RemoveReceiverInterest(lastEntry->fReceiver, FW_CInterest(notifier, lastEntry->fMessage), false);
- delete lastEntry->fTagCollection;
- delete lastEntry;
- }
- } while (lastEntry);
-
- delete interestList;
- fNotifierInterestMap.Remove(notifierID);
- notifier->PrivSetNotifierID(0);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivInterestSpace::SetReceiverIsConnected
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivInterestSpace::SetReceiverIsConnected(FW_MReceiver* receiver, FW_Boolean connected)
- {
- FW_ObjectID receiverID = receiver->PrivGetReceiverID();
- if (receiverID == 0)
- return;
-
- FW_CPrivReceiverInterestPair* pair = fReceiverInterestMap.Find(receiverID);
- FW_ASSERT(pair);
- FW_ASSERT(pair->fValue.fReceiver == receiver);
-
- FW_TOrderedCollectionIterator<FW_CInterest> iter(pair->fValue.fInterestList);
- for (FW_CInterest* interest = iter.First(); iter.IsNotComplete(); interest = iter.Next())
- {
- if (connected)
- AddNotifierInterest(receiver, *interest);
- else
- RemoveNotifierInterest(receiver, *interest);
- }
- }