42#if SMTG_CPP11_STDLIBSUPPORT
51#define NON_EXISTING_DEPENDENCY_CHECK 0
52#define CLASS_NAME_TRACKED DEVELOPMENT
58DEF_CLASS_IID (IUpdateManager)
61const uint32 kHashSize = (1 << 8);
62const uint32 kMapSize = 1024 * 10;
65inline uint32 hashPointer (
void* p)
67 return (uint32)((uint64 (p) >> 12) & (kHashSize - 1));
71inline IPtr<FUnknown> getUnknownBase (FUnknown* unknown)
73 FUnknown* result =
nullptr;
75 unknown->queryInterface (FUnknown::iid, (
void**)&result);
77 return owned (result);
84 Dependency (FUnknown* o, IDependent* d)
85 : obj (o), dep (d), objClass (nullptr), depClass (nullptr)
89 inline bool operator== (
const Dependency& d)
const {
return obj == d.obj; }
90 inline bool operator!= (
const Dependency& d)
const {
return obj != d.obj; }
91 inline bool operator< (
const Dependency& d)
const {
return obj < d.obj; }
92 inline bool operator> (
const Dependency& d)
const {
return obj > d.obj; }
107 inline bool operator== (
const DeferedChange& d)
const {
return obj == d.obj; }
108 inline bool operator!= (
const DeferedChange& d)
const {
return obj != d.obj; }
117 : obj (o), dependents (d), count (c)
125 return d.obj == obj && d.dependents == dependents;
131using DeferedChangeListIterConst = DeferedChangeList::const_iterator;
132using DeferedChangeListIter = DeferedChangeList::iterator;
135using UpdateDataListIterConst = UpdateDataList::const_iterator;
137#if CLASS_NAME_TRACKED
142using DependentListIter = DependentList::iterator;
143using DependentListIterConst = DependentList::const_iterator;
145#if SMTG_CPP11_STDLIBSUPPORT
150using DependentMapIter = DependentMap::iterator;
151using DependentMapIterConst = DependentMap::const_iterator;
161void updateDone (
FUnknown* unknown, int32 message)
163 if (message != IDependent::kDestroyed)
173static int32 countEntries (Update::DependentMap& map)
176 Update::DependentMapIterConst iterMap = map.begin ();
177 while (iterMap != map.end ())
179 const Update::DependentList& list = iterMap->second;
180 Update::DependentListIterConst iterList = list.begin ();
181 while (iterList != list.end ())
192UpdateHandler::UpdateHandler ()
194 table = NEW Update::Table;
200UpdateHandler::~UpdateHandler ()
212 if (!unknown || !_dependent)
217#if CLASS_NAME_TRACKED
218 Update::Dependency dependent (unknown, _dependent);
222 dependent.objClass = obj->
isA ();
225 dependent.depClass = obj->
isA ();
231 Update::DependentMapIter it = map.
find (unknown);
232 if (it == map.
end ())
235 list.push_back (dependent);
240 (*it).second.push_back (dependent);
257 if (unknown ==
nullptr && dependent ==
nullptr)
262 Update::UpdateDataListIterConst iter = table->updateData.
begin ();
263 while (iter != table->updateData.
end ())
265 if ((*iter).obj == unknown || unknown ==
nullptr)
267 for (uint32 count = 0; count < (*iter).count; count++)
269 if ((*iter).dependents[count] == dependent)
270 (*iter).dependents[count] =
nullptr;
276 if (unknown ==
nullptr)
278 for (uint32 j = 0; j < Update::kHashSize; j++)
281 Update::DependentMapIter iterMap = map.
begin ();
282 while (iterMap != map.
end ())
285 Update::DependentListIter iterList = list.begin ();
286 bool listIsEmpty =
false;
288 while (iterList != list.end ())
290#if CLASS_NAME_TRACKED
291 if ((*iterList).dep == dependent)
293 if ((*iterList) == dependent)
296 eraseCount = list.size ();
297 if (list.size () == 1u)
304 iterList = list.erase (iterList);
314 iterMap = map.
erase (iterMap);
322 bool mustFlush =
true;
325 Update::DependentMapIter iterList = map.
find (unknown);
327#if NON_EXISTING_DEPENDENCY_CHECK
328 SMTG_ASSERT (iterList != map.
end () &&
"ERROR: Trying to remove a non existing dependency!")
330 if (iterList != map.
end ())
332 if (dependent ==
nullptr)
334 eraseCount = iterList->second.size ();
335 map.
erase (iterList);
340 Update::DependentListIter iterDependentlist = dependentlist.
begin ();
341 while (iterDependentlist != dependentlist.
end ())
343#if CLASS_NAME_TRACKED
344 if ((*iterDependentlist).dep == dependent)
346 if ((*iterDependentlist) == dependent)
349 iterDependentlist = dependentlist.
erase (iterDependentlist);
351 if (dependentlist.
empty ())
353 map.
erase (iterList);
373tresult UpdateHandler::doTriggerUpdates (
FUnknown* u, int32 message,
bool suppressUpdateDone)
381 IDependent* smallDependents[Update::kMapSize / 10];
383 int32 maxDependents = Update::kMapSize / 10;
390 Update::DependentMapIterConst iterList = map.
find (unknown);
391 if (iterList != map.
end ())
394 Update::DependentListIterConst iterDependentlist = dependentlist.
begin ();
395 while (iterDependentlist != dependentlist.
end ())
397#if CLASS_NAME_TRACKED
398 dependents[count] = (*iterDependentlist).dep;
400 dependents[count] = *iterDependentlist;
404 if (count >= maxDependents)
406 if (dependents == smallDependents)
408 dependents = NEW
IDependent*[Update::kMapSize];
409 memcpy (dependents, smallDependents, count *
sizeof (dependents[0]));
410 maxDependents = Update::kMapSize;
414 SMTG_WARNING (
"Dependency overflow")
425 Update::UpdateData data (unknown, dependents, count);
434 dependents[i]->
update (unknown, message);
438 if (dependents != smallDependents)
450 if (suppressUpdateDone ==
false)
451 Update::updateDone (unknown, message);
453 return count > 0 ? kResultTrue : kResultFalse;
459 return doTriggerUpdates (u, message,
false);
472 Update::DependentMapIterConst iterList = map.
find (unknown);
474 bool hasDependency = (iterList != map.
end ());
475 if (hasDependency ==
false)
477 Update::updateDone (unknown, message);
482 Update::DeferedChangeListIterConst iter = table->defered.
begin ();
483 while (iter != table->defered.
end ())
485 if ((*iter).obj == unknown && (*iter).msg == message)
508 while (table->defered.
empty () ==
false)
514 int32 msg = table->defered.
front ().msg;
518 bool canSignal =
true;
519 Update::UpdateDataListIterConst iter = table->updateData.
begin ();
520 while (iter != table->updateData.
end ())
522 if ((*iter).obj == obj)
550 Update::DeferedChangeListIter it =
552 if (it == table->defered.
end ())
558 if ((*it).obj !=
nullptr)
560 int32 msg = (*it).msg;
561 table->defered.
erase (it);
565 bool canSignal =
true;
566 Update::UpdateDataListIterConst iter = table->updateData.
begin ();
567 while (iter != table->updateData.
end ())
569 if ((*iter).obj ==
object)
591 if (deferedAgain.
empty () ==
false)
595 Update::DeferedChangeListIterConst iter = deferedAgain.
begin ();
596 while (iter != deferedAgain.
end ())
619 if (iter != table->defered.
end ())
620 table->defered.
erase (iter);
629size_t UpdateHandler::countDependencies (
FUnknown*
object)
638 Update::DependentMapIter iterList = map.
find (unknown);
639 if (iterList != map.
end ())
640 return iterList->second.size ();
644 for (uint32 j = 0; j < Update::kHashSize; j++)
646 Update::DependentMap& map = table->depMap[j];
647 res += countEntries (map);
655bool UpdateHandler::checkDeferred (FUnknown*
object)
657 IPtr<FUnknown> unknown = Update::getUnknownBase (
object);
661 Update::DeferedChange tmp (unknown);
662 Update::DeferedChangeListIterConst it =
664 if (it != table->defered.
end ())
671bool UpdateHandler::hasDependencies (FUnknown* u)
673 IPtr<FUnknown> unknown = Update::getUnknownBase (u);
679 Update::DependentMap& map = table->depMap[Update::hashPointer (unknown)];
680 Update::DependentMapIterConst iterList = map.
find (unknown);
681 bool hasDependency = (iterList != map.end ());
683 return hasDependency;
687void UpdateHandler::printForObject (FObject* obj)
const
689 IPtr<FUnknown> unknown = Update::getUnknownBase (obj);
693 FUnknownPtr<IDependent> dep (obj);
697 Update::DependentMap& map = table->depMap[Update::hashPointer (unknown)];
698 Update::DependentMapIterConst iterList = map.
begin ();
699 while (iterList != map.end ())
701 const Update::DependentList& dependentlist = (*iterList).second;
702 Update::DependentListIterConst iterDependentlist = dependentlist.
begin ();
703 while (iterDependentlist != dependentlist.end ())
705#if CLASS_NAME_TRACKED
706 if ((*iterList).first == unknown || (*iterDependentlist).dep == dep.getInterface ())
710 FDebugPrint (
"Dependencies for object %8" FORMAT_INT64A
" %s\n", (uint64)obj,
714 FDebugPrint (
"%s %8" FORMAT_INT64A
"\n <- %s %8" FORMAT_INT64A
"\n",
715 (*iterDependentlist).depClass, (uint64) (*iterDependentlist).dep,
716 (*iterDependentlist).objClass, (uint64) ((*iterList).first));
719 if ((*iterList).first == unknown || (*iterDependentlist) == dep.getInterface ())
723 FDebugPrint (
"Dependencies for object %8" FORMAT_INT64A
" %s\n", (uint64)obj,
727 FDebugPrint (
"%8" FORMAT_INT64A
"\n <- %8" FORMAT_INT64A
"\n",
728 (uint64) (*iterDependentlist), (uint64) ((*iterList).first));
FGuard - automatic object for locks.
void unlock() SMTG_OVERRIDE
Disables lock.
void lock() SMTG_OVERRIDE
Enables lock.
Implements FUnknown and IDependent.
static void setUpdateHandler(IUpdateHandler *handler)
set method for the local attribute
static FObject * unknownToObject(FUnknown *unknown)
pointer conversion from FUnknown to FObject
static IUpdateHandler * getUpdateHandler()
get method for the local attribute
virtual void updateDone(int32)
empty virtual method that should be overridden by derived classes
virtual FClassID isA() const
a local alternative to getFClassID ()
The basic interface of all interfaces.
A dependent will get notified about changes of a model.
virtual void PLUGIN_API update(FUnknown *changedUnknown, int32 message)=0
Inform the dependent, that the passed FUnknown has changed.
IPtr - Smart pointer template class.
tresult PLUGIN_API addDependent(FUnknown *object, IDependent *dependent) SMTG_OVERRIDE
register
tresult PLUGIN_API removeDependent(FUnknown *object, IDependent *dependent, size_t &earseCount)
unregister
tresult PLUGIN_API triggerUpdates(FUnknown *object, int32 message) SMTG_OVERRIDE
send
tresult PLUGIN_API triggerDeferedUpdates(FUnknown *object=nullptr) SMTG_OVERRIDE
send pending messages send by
tresult PLUGIN_API deferUpdates(FUnknown *object, int32 message) SMTG_OVERRIDE
send
tresult PLUGIN_API cancelUpdates(FUnknown *object) SMTG_OVERRIDE
cancel pending messages send by
#define SMTG_ASSERT(f)
if DEVELOPMENT is not set, these macros will do nothing.
IPtr< I > owned(I *p)
Assigning newly created object to an IPtr.