#pragma once #include #include #include "PatchCode.h" #include "PatchHeap.h" /// @brief Class representing a collection of patch codes. class PatchCodeCollection { private: using create_patch_code_func_t = PatchCode* (*)(PatchCodeCollection& patchCodeCollection); public: PatchCodeCollection() { _patchCodeEntries.fill({ 0, nullptr }); } PatchCodeCollection(const PatchCodeCollection&) = delete; /// @brief Adds a unique patch code to the collection. If the same patch code is added another time, it will be duplicated. /// @tparam T The type of patch code. /// @tparam ...Args The argument types for the patch code constructor. /// @param ...args The arguments for the patch code constructor. /// @return A pointer to the patch code. template requires std::derived_from const T* AddUniquePatchCode(Args&&... args) { T* patchCode = new T(std::forward(args)...); AddUniquePatchCode(patchCode); return patchCode; } /// @brief Gets or adds a shared patch code from/to the collection. /// If the same patch code is requested another time, the same instance will be returned. /// @tparam T The type of patch code. /// @param factoryFunction A factory function that produces a pointer to the patch code class (T*). /// @return A pointer to the patch code. template requires std::derived_from>, PatchCode> auto GetOrAddSharedPatchCode(T factoryFunction) // return type of the factory function converted from a pointer to a pointer to const -> std::add_pointer_t>> { u32 id = GetPatchCodeId>(); auto& entry = GetOrAddSharedPatchCode(id); if (entry.type == 0) { entry.type = id; // claim this slot before calling the factory function entry.patchCode = factoryFunction(); } return static_cast(entry.patchCode); } /// @brief Copies all patch codes to their target location. void CopyAllToTarget() const; private: struct PatchCodeEntry { u32 type; PatchCode* patchCode; }; std::array _patchCodeEntries; void AddUniquePatchCode(PatchCode* patchCode); PatchCodeEntry& GetOrAddSharedPatchCode(u32 id); template static u32 GetPatchCodeId() { static const char typeId = 0; return (u32)&typeId; } };