blob: 394b9d15ccde368d7e1a505a457c428301b3de8e [file]
#ifndef _RIVE_DEPENDENCY_HELPER_HPP_
#define _RIVE_DEPENDENCY_HELPER_HPP_
#include "rive/component_dirt.hpp"
#include "rive/lazy_vector.hpp"
namespace rive
{
class Component;
// CRTP base. Holds a list of dependents; defers the "root" pointer to the
// derived class so we don't store it twice. Derived must expose:
// T* dependencyRoot() const;
//
// Saves 8 B per Component / per ViewModelInstanceValue compared to the
// previous design where DependencyHelper also stored its own T* root pointer
// duplicating whatever the owner already had (Component::m_Artboard,
// ViewModelInstanceValue::m_viewModelInstance).
template <typename T, typename U, typename Derived> class DependencyHelper
{
// Most Components have no dependents (only the dependency graph's
// interior nodes do); for those, a single null pointer beats a 24 B
// vector header by 16 B per Component.
//
// Hot path: addDirtToDependents() is called once per dirt cascade,
// potentially many times per frame. The LazyVector null check is a
// single load + branch, comparable to (or cheaper than) loading the
// 3-pointer vector header inline.
LazyVector<U*> m_Dependents;
public:
void addDependent(U* component) { m_Dependents.pushUnique(component); }
void removeDependent(U* component) { m_Dependents.eraseAll(component); }
// Cascade dirt to every registered dependent. Named distinctly from
// Component::addDirt (and the like on the derived class) so the inherited
// method doesn't clash with the derived class's self-dirty method.
//
// Hot path: cascaded every dirt, often many times per frame. The empty()
// early-out is a single load + branch when the wrapper's pointer is null,
// identical in cost to the raw-pointer version this replaced.
void addDirtToDependents(ComponentDirt value)
{
if (m_Dependents.empty())
{
return;
}
for (auto* d : m_Dependents)
{
d->addDirt(value, true);
}
}
void onComponentDirty(U* component)
{
static_cast<Derived*>(this)->dependencyRoot()->onComponentDirty(
component);
}
const std::vector<U*>& dependents() const { return m_Dependents.view(); }
};
} // namespace rive
#endif