funny shared_ptr implementation

This commit is contained in:
altalk23 2024-01-15 17:57:43 +03:00
parent ab436bd7c3
commit 165f05fcb4
13 changed files with 80 additions and 51 deletions

View file

@ -16,13 +16,14 @@ namespace geode {
private:
class Impl;
std::shared_ptr<Impl> m_impl;
explicit Hook(std::shared_ptr<Impl>&& impl);
~Hook();
friend class Mod;
friend class Loader;
public:
explicit Hook(std::shared_ptr<Impl>&& impl);
/**
* Create a hook at an address. The hook is enabled immediately. By
* default, the hook is placed at the end of the detour list; however,
@ -37,7 +38,7 @@ namespace geode {
* @returns The created hook, or an error. Make sure to add the created
* hook to the mod that owns it using mod->claimHook!
*/
static Hook* create(
static std::shared_ptr<Hook> create(
void* address,
void* detour,
std::string const& displayName,
@ -46,7 +47,7 @@ namespace geode {
);
template<class DetourType>
static Hook* create(
static std::shared_ptr<Hook> create(
void* address,
DetourType detour,
std::string const& displayName,
@ -144,14 +145,15 @@ namespace geode {
private:
class Impl;
std::shared_ptr<Impl> m_impl;
explicit Patch(std::shared_ptr<Impl>&& impl);
~Patch();
friend class Mod;
friend class Loader;
public:
static Patch* create(void* address, const ByteVector& patch);
explicit Patch(std::shared_ptr<Impl>&& impl);
static std::shared_ptr<Patch> create(void* address, const ByteVector& patch);
Patch(Patch const&) = delete;
Patch operator=(Patch const&) = delete;

View file

@ -251,8 +251,8 @@ namespace geode {
tulip::hook::HookMetadata const& hookMetadata = tulip::hook::HookMetadata()
) {
auto hook = Hook::create(address, detour, displayName, convention, hookMetadata);
GEODE_UNWRAP(this->claimHook(hook));
return Ok(hook);
GEODE_UNWRAP_INTO(auto ptr, this->claimHook(std::move(hook)));
return Ok(ptr);
}
Result<Hook*> hook(
@ -261,11 +261,11 @@ namespace geode {
tulip::hook::HookMetadata const& hookMetadata
) {
auto hook = Hook::create(address, detour, displayName, handlerMetadata, hookMetadata);
GEODE_UNWRAP(this->claimHook(hook));
return Ok(hook);
GEODE_UNWRAP_INTO(auto ptr, this->claimHook(std::move(hook)));
return Ok(ptr);
}
Result<> claimHook(Hook* hook);
Result<Hook*> claimHook(std::shared_ptr<Hook>&& hook);
Result<> disownHook(Hook* hook);
@ -284,11 +284,11 @@ namespace geode {
*/
Result<Patch*> patch(void* address, ByteVector const& data) {
auto patch = Patch::create(address, data);
GEODE_UNWRAP(this->claimPatch(patch));
return Ok(patch);
GEODE_UNWRAP_INTO(auto ptr, this->claimPatch(std::move(patch)));
return Ok(ptr);
}
Result<> claimPatch(Patch* patch);
Result<Patch*> claimPatch(std::shared_ptr<Patch>&& patch);
Result<> disownPatch(Patch* patch);

View file

@ -70,13 +70,13 @@ namespace geode::modifier {
template <class ModifyDerived>
class ModifyBase {
public:
std::map<std::string, Hook*> m_hooks;
std::map<std::string, std::shared_ptr<Hook>> m_hooks;
Result<Hook*> getHook(std::string const& name) {
if (m_hooks.find(name) == m_hooks.end()) {
return Err("Hook not in this modify");
}
return Ok(m_hooks[name]);
return Ok(m_hooks[name].get());
}
Result<> setHookPriority(std::string const& name, int32_t priority) {
@ -94,11 +94,18 @@ namespace geode::modifier {
auto test = static_cast<ModifyDerived*>(this);
test->ModifyDerived::apply();
ModifyDerived::Derived::onModify(*this);
std::vector<std::string> added;
for (auto& [uuid, hook] : m_hooks) {
auto res = Mod::get()->claimHook(hook);
auto res = Mod::get()->claimHook(std::move(hook));
if (!res) {
log::error("Failed to claim hook {}: {}", hook->getDisplayName(), res.error());
}
else {
added.push_back(uuid);
}
}
for (auto& uuid : added) {
m_hooks.erase(uuid);
}
}

View file

@ -35,7 +35,7 @@ namespace geode {
* @returns The created hook, or an error.
*/
template <class Func>
static Result<Hook*> create(std::string const& className, std::string const& selectorName, Func function, tulip::hook::HookMetadata const& metadata = tulip::hook::HookMetadata()) {
static Result<std::shared_ptr<Hook>> create(std::string const& className, std::string const& selectorName, Func function, tulip::hook::HookMetadata const& metadata = tulip::hook::HookMetadata()) {
GEODE_UNWRAP_INTO(auto imp, geode::hook::getObjcMethodImp(className, selectorName));
return Ok(Hook::create(
@ -59,7 +59,7 @@ namespace geode {
* @returns The created hook, or an error.
*/
template <class Func>
static Result<Hook*> create(std::string const& className, std::string const& selectorName, Func function, void(*empty)(), tulip::hook::HookMetadata const& metadata = tulip::hook::HookMetadata()) {
static Result<std::shared_ptr<Hook>> create(std::string const& className, std::string const& selectorName, Func function, void(*empty)(), tulip::hook::HookMetadata const& metadata = tulip::hook::HookMetadata()) {
GEODE_UNWRAP(geode::hook::addObjcMethod(className, selectorName, (void*)empty));
return ObjcHook::create(className, selectorName, function, metadata);

View file

@ -6,7 +6,7 @@ using namespace geode::prelude;
Hook::Hook(std::shared_ptr<Impl>&& impl) : m_impl(std::move(impl)) { m_impl->m_self = this; }
Hook::~Hook() = default;
Hook* Hook::create(
std::shared_ptr<Hook> Hook::create(
void* address,
void* detour,
std::string const& displayName,

View file

@ -29,7 +29,7 @@ Hook::Impl::~Impl() {
}
}
Hook* Hook::Impl::create(
std::shared_ptr<Hook> Hook::Impl::create(
void* address,
void* detour,
std::string const& displayName,
@ -39,7 +39,9 @@ Hook* Hook::Impl::create(
auto impl = std::make_shared<Impl>(
address, detour, displayName, handlerMetadata, hookMetadata
);
return new Hook(std::move(impl));
return std::shared_ptr<Hook>(new Hook(std::move(impl)), [](Hook* hook) {
delete hook;
});
}
Result<> Hook::Impl::enable() {

View file

@ -22,7 +22,7 @@ public:
);
~Impl();
static Hook* create(
static std::shared_ptr<Hook> create(
void* address,
void* detour,
std::string const& displayName,
@ -31,7 +31,7 @@ public:
);
template<class DetourType>
static Hook* create(
static std::shared_ptr<Hook> create(
void* address,
DetourType detour,
std::string const& displayName,

View file

@ -121,8 +121,8 @@ void Mod::registerCustomSetting(std::string_view const key, std::unique_ptr<Sett
return m_impl->registerCustomSetting(key, std::move(value));
}
Result<> Mod::claimHook(Hook* hook) {
return m_impl->claimHook(hook);
Result<Hook*> Mod::claimHook(std::shared_ptr<Hook>&& hook) {
return m_impl->claimHook(std::move(hook));
}
Result<> Mod::disownHook(Hook* hook) {
@ -133,8 +133,8 @@ std::vector<Hook*> Mod::getHooks() const {
return m_impl->getHooks();
}
Result<> Mod::claimPatch(Patch* patch) {
return m_impl->claimPatch(patch);
Result<Patch*> Mod::claimPatch(std::shared_ptr<Patch>&& patch) {
return m_impl->claimPatch(std::move(patch));
}
Result<> Mod::disownPatch(Patch* patch) {

View file

@ -132,11 +132,19 @@ bool Mod::Impl::needsEarlyLoad() const {
}
std::vector<Hook*> Mod::Impl::getHooks() const {
return m_hooks;
std::vector<Hook*> ret;
for (auto& hook : m_hooks) {
ret.push_back(hook.get());
}
return ret;
}
std::vector<Patch*> Mod::Impl::getPatches() const {
return m_patches;
std::vector<Patch*> ret;
for (auto& patch : m_patches) {
ret.push_back(patch.get());
}
return ret;
}
// Settings and saved values
@ -441,27 +449,30 @@ bool Mod::Impl::depends(std::string_view const id) const {
// Hooks
Result<> Mod::Impl::claimHook(Hook* hook) {
Result<Hook*> Mod::Impl::claimHook(std::shared_ptr<Hook>&& hook) {
auto res1 = hook->m_impl->setOwner(m_self);
if (!res1) {
return Err("Cannot claim hook: {}", res1.unwrapErr());
}
m_hooks.push_back(hook);
auto ptr = hook.get();
m_hooks.push_back(std::move(hook));
if (!this->isEnabled() || !hook->getAutoEnable())
return Ok();
return Ok(ptr);
if (!LoaderImpl::get()->isReadyToHook()) {
LoaderImpl::get()->addUninitializedHook(hook, m_self);
return Ok();
LoaderImpl::get()->addUninitializedHook(ptr, m_self);
return Ok(ptr);
}
auto res2 = hook->enable();
auto res2 = ptr->enable();
if (!res2) {
return Err("Cannot enable hook: {}", res2.unwrapErr());
}
return Ok();
return Ok(ptr);
}
Result<> Mod::Impl::disownHook(Hook* hook) {
@ -473,7 +484,9 @@ Result<> Mod::Impl::disownHook(Hook* hook) {
if (!res1) {
return Err("Cannot disown hook: {}", res1.unwrapErr());
}
m_hooks.erase(std::find(m_hooks.begin(), m_hooks.end(), hook));
m_hooks.erase(std::find_if(m_hooks.begin(), m_hooks.end(), [&](auto& a) {
return a.get() == hook;
}));
if (!this->isEnabled() || !hook->getAutoEnable())
return Ok();
@ -488,22 +501,23 @@ Result<> Mod::Impl::disownHook(Hook* hook) {
// Patches
Result<> Mod::Impl::claimPatch(Patch* patch) {
Result<Patch*> Mod::Impl::claimPatch(std::shared_ptr<Patch>&& patch) {
auto res1 = patch->m_impl->setOwner(m_self);
if (!res1) {
return Err("Cannot claim patch: {}", res1.unwrapErr());
}
m_patches.push_back(patch);
auto ptr = patch.get();
m_patches.push_back(std::move(patch));
if (!this->isEnabled() || !patch->getAutoEnable())
return Ok();
return Ok(ptr);
auto res2 = patch->enable();
auto res2 = ptr->enable();
if (!res2) {
return Err("Cannot enable patch: {}", res2.unwrapErr());
}
return Ok();
return Ok(ptr);
}
Result<> Mod::Impl::disownPatch(Patch* patch) {
@ -515,7 +529,9 @@ Result<> Mod::Impl::disownPatch(Patch* patch) {
if (!res1) {
return Err("Cannot disown patch: {}", res1.unwrapErr());
}
m_patches.erase(std::find(m_patches.begin(), m_patches.end(), patch));
m_patches.erase(std::find_if(m_patches.begin(), m_patches.end(), [&](auto& a) {
return a.get() == patch;
}));
if (!this->isEnabled() || !patch->getAutoEnable())
return Ok();

View file

@ -18,11 +18,11 @@ namespace geode {
/**
* Hooks owned by this mod
*/
std::vector<Hook*> m_hooks;
std::vector<std::shared_ptr<Hook>> m_hooks;
/**
* Patches owned by this mod
*/
std::vector<Patch*> m_patches;
std::vector<std::shared_ptr<Patch>> m_patches;
/**
* Whether the mod is enabled or not
*/
@ -113,11 +113,11 @@ namespace geode {
SettingValue* getSetting(std::string_view const key) const;
void registerCustomSetting(std::string_view const key, std::unique_ptr<SettingValue> value);
Result<> claimHook(Hook* hook);
Result<Hook*> claimHook(std::shared_ptr<Hook>&& hook);
Result<> disownHook(Hook* hook);
[[nodiscard]] std::vector<Hook*> getHooks() const;
Result<> claimPatch(Patch* patch);
Result<Patch*> claimPatch(std::shared_ptr<Patch>&& patch);
Result<> disownPatch(Patch* patch);
[[nodiscard]] std::vector<Patch*> getPatches() const;

View file

@ -6,7 +6,7 @@ using namespace geode::prelude;
Patch::Patch(std::shared_ptr<Impl>&& impl) : m_impl(std::move(impl)) { m_impl->m_self = this; }
Patch::~Patch() = default;
Patch* Patch::create(void* address, const ByteVector& patch) {
std::shared_ptr<Patch> Patch::create(void* address, const ByteVector& patch) {
return Impl::create(address, patch);
}

View file

@ -31,11 +31,13 @@ static ByteVector readMemory(void* address, size_t amount) {
return ret;
}
Patch* Patch::Impl::create(void* address, const geode::ByteVector& patch) {
std::shared_ptr<Patch> Patch::Impl::create(void* address, const geode::ByteVector& patch) {
auto impl = std::make_shared<Impl>(
address, readMemory(address, patch.size()), patch
);
return new Patch(std::move(impl));
return std::shared_ptr<Patch>(new Patch(std::move(impl)), [](Patch* patch) {
delete patch;
});
}
Result<> Patch::Impl::enable() {

View file

@ -13,7 +13,7 @@ public:
Impl(void* address, ByteVector original, ByteVector patch);
~Impl();
static Patch* create(void* address, const ByteVector& patch);
static std::shared_ptr<Patch> create(void* address, const ByteVector& patch);
Patch* m_self = nullptr;
void* m_address;