Skip to content

Instantly share code, notes, and snippets.

@Shtille
Created March 11, 2026 16:53
Show Gist options
  • Select an option

  • Save Shtille/b60a6b5c0609f7c49dcc4b3b487302af to your computer and use it in GitHub Desktop.

Select an option

Save Shtille/b60a6b5c0609f7c49dcc4b3b487302af to your computer and use it in GitHub Desktop.
Children resolver
/**
* The main idea of this class is to call some function when all children are ready.
*/
template<class Parent, class Child>
class ChildResolver
{
typedef std::vector<Child*> ChildList;
typedef std::unordered_set<Child*> ChildSet;
typedef std::function<ChildList(Parent*)> ChildListFunction;
typedef std::function<bool(Child*)> ChildReadyFunction;
typedef std::function<void(Parent*)> ParentReadyFunction;
public:
ChildResolver(ChildListFunction child_list_func, ChildReadyFunction child_ready_func, ParentReadyFunction parent_ready_func)
: m_childListFunction(child_list_func)
, m_childReadyFunction(child_ready_func)
, m_parentReadyFunction(parent_ready_func)
{}
// OnAppendRenderObject call this
void Add(Parent* parent)
{
ChildList list = m_childListFunction(parent);
auto pair = m_parentToChildrenMap.emplace(parent, std::move(list));
ChildList* children = &pair.first->second;
ChildSet notReadySet;
for (Child* child : *children)
{
if (!m_childReadyFunction(child))
notReadySet.insert(child);
m_childToChildrenMap.emplace(child, std::make_pair<ChildList*, Parent*>(children, parent));
}
m_notReadyChildren.emplace(children, std::move(notReadySet));
}
// OnRemoveRenderObject call this
void Remove(Parent* parent)
{
auto it = m_parentToChildrenMap.find(parent);
ChildList* children = &it->second;
for (Child* child : *children)
{
auto range = m_childToChildrenMap.equal_range(child);
for (auto itr = range.first; itr != range.second;)
if (itr->second.first == children)
itr = m_childToChildrenMap.erase(itr);
else
++itr;
}
m_notReadyChildren.erase(children);
m_parentToChildrenMap.erase(it);
}
// call from outside
void OnChildReady(Child* child)
{
// Find all children groups by child
auto range = m_childToChildrenMap.equal_range(child);
for (auto itr = range.first; itr != range.second; ++itr)
{
ChildList* children = itr->second.first;
// Mark child ready (remove it from not ready set)
auto it = m_notReadyChildren.find(children);
if (it != m_notReadyChildren.end())
it->second.erase(child);
// Check if all children are ready
bool groupReady = it->second.empty();
if (groupReady)
{
Parent* parent = itr->second.second;
m_parentReadyFunction(parent);
}
}
}
private:
std::unordered_map<Parent*, ChildList> m_parentToChildrenMap;
std::unordered_map<ChildList*, ChildSet> m_notReadyChildren;
std::unordered_multimap<Child*, std::pair<ChildList*, Parent*>> m_childToChildrenMap;
ChildListFunction m_childListFunction;
ChildReadyFunction m_childReadyFunction;
ParentReadyFunction m_parentReadyFunction;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment