Files
pico-loader/arm9/source/patches/PatchCodeCollection.h
2025-11-23 17:14:17 +01:00

77 lines
2.6 KiB
C++

#pragma once
#include <array>
#include <concepts>
#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 <typename T, typename... Args> requires std::derived_from<T, PatchCode>
const T* AddUniquePatchCode(Args&&... args)
{
T* patchCode = new T(std::forward<Args>(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 <typename T> requires std::derived_from<std::remove_pointer_t<std::invoke_result_t<T>>, PatchCode>
auto GetOrAddSharedPatchCode(T factoryFunction)
// return type of the factory function converted from a pointer to a pointer to const
-> std::add_pointer_t<std::add_const_t<std::remove_pointer_t<decltype(factoryFunction())>>>
{
u32 id = GetPatchCodeId<std::remove_pointer_t<decltype(factoryFunction())>>();
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<decltype(factoryFunction())>(entry.patchCode);
}
/// @brief Copies all patch codes to their target location.
void CopyAllToTarget() const;
private:
struct PatchCodeEntry
{
u32 type;
PatchCode* patchCode;
};
std::array<PatchCodeEntry, 64> _patchCodeEntries;
void AddUniquePatchCode(PatchCode* patchCode);
PatchCodeEntry& GetOrAddSharedPatchCode(u32 id);
template <class T>
static u32 GetPatchCodeId()
{
static const char typeId = 0;
return (u32)&typeId;
}
};