/** * @file llinstancetrackersubclass.h * @author Nat Goodspeed * @date 2022-12-09 * @brief Intermediate class to get subclass-specific types from * LLInstanceTracker instance-retrieval methods. * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ */ #if ! defined(LL_LLINSTANCETRACKERSUBCLASS_H) #define LL_LLINSTANCETRACKERSUBCLASS_H #include // std::shared_ptr, std::weak_ptr /** * Derive your subclass S of a subclass T of LLInstanceTracker from * LLInstanceTrackerSubclass to perform appropriate downcasting and * filtering for LLInstanceTracker access methods. * * LLInstanceTracker uses CRTP, so that getWeak(), getInstance(), snapshot * and instance_snapshot return pointers and references to T. The trouble is * that subclasses T0 and T1 derived from T also get pointers and references * to their base class T, requiring explicit downcasting. Moreover, * T0::getInstance() shouldn't find an instance of any T subclass other than * T0. Nor should T0::snapshot. * * @code * class Tracked: public LLInstanceTracker * { * private: * using super = LLInstanceTracker; * public: * Tracked(const std::string& name): super(name) {} * // All references to Tracked::ptr_t, Tracked::getInstance() etc. * // appropriately use Tracked. * // ... * }; * * // But now we derive SubTracked from Tracked. We need SubTracked::ptr_t, * // SubTracked::getInstance() etc. to use SubTracked, not Tracked. * // This LLInstanceTrackerSubclass specialization is itself derived from * // Tracked. * class SubTracked: public LLInstanceTrackerSubclass * { * private: * using super = LLInstanceTrackerSubclass; * public: * // LLInstanceTrackerSubclass's constructor forwards to Tracked's. * SubTracked(const std::string& name): super(name) {} * // SubTracked::getInstance() returns std::shared_ptr, etc. * // ... * @endcode */ template class LLInstanceTrackerSubclass: public T { public: using ptr_t = std::shared_ptr; using weak_t = std::weak_ptr; // forward any constructor call to the corresponding T ctor template LLInstanceTrackerSubclass(ARGS&&... args): T(std::forward(args)...) {} weak_t getWeak() { // call base-class getWeak(), try to lock, downcast to SUBCLASS return std::dynamic_pointer_cast(T::getWeak().lock()); } template static ptr_t getInstance(const KEY& k) { return std::dynamic_pointer_cast(T::getInstance(k)); } using snapshot = typename T::template snapshot_of; using instance_snapshot = typename T::template instance_snapshot_of; using key_snapshot = typename T::template key_snapshot_of; static size_t instanceCount() { // T::instanceCount() lies because our snapshot, et al., won't // necessarily return all the T instances -- only those that are also // SUBCLASS instances. Count those. size_t count = 0; for (const auto& pair : snapshot()) ++count; return count; } }; #endif /* ! defined(LL_LLINSTANCETRACKERSUBCLASS_H) */