You've already forked pico-loader
mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-01-09 16:28:35 -08:00
77 lines
2.6 KiB
C++
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;
|
|
}
|
|
}; |