diff --git a/include/SharedPtr.h b/include/SharedPtr.h new file mode 100644 index 0000000..cc711be --- /dev/null +++ b/include/SharedPtr.h @@ -0,0 +1,106 @@ +#pragma once +#include "global.h" + +template +class SharedPtr +{ +private: + T *data = nullptr; + + struct SharedLock + { + struct vtable_counted_base + { + void(__thiscall *dtr)(SharedLock *); + void(__thiscall *dispose)(SharedLock *); + void(__thiscall *destroy)(SharedLock *); + void *(__thiscall *get_deleter)(SharedLock *); + } *vtable; + unsigned use_count_; + unsigned weak_count_; + void *px_; + } *lock = nullptr; + +public: + SharedPtr() : data{nullptr}, lock{nullptr} + { + } + + SharedPtr(const SharedPtr &other) + { + data = other.data; + lock = other.lock; + Lock(); + } + + SharedPtr(SharedPtr &&other) + { + data = other.data; + lock = other.lock; + other.data = nullptr; + other.lock = nullptr; + } + + SharedPtr &operator=(const SharedPtr &other) + { + Release(); + data = other.data; + lock = other.lock; + Lock(); + } + + SharedPtr &operator=(SharedPtr &&other) + { + Release(); + data = other.data; + lock = other.lock; + other.data = nullptr; + other.lock = nullptr; + } + + T *Get() const + { + return data; + } + + bool Valid() const + { + return data != nullptr; + } + + ~SharedPtr() + { + Release(); + } + + void Release() + { + InternalRelease(); + lock = nullptr; + data = nullptr; + } + +private: + void InternalRelease() + { + if (!lock) + return; + + if (InterlockedExchangeAdd(&lock->use_count_, -1)) + return; + + lock->vtable->dispose(lock); + if (InterlockedExchangeAdd(&lock->weak_count_, -1)) + return; + + lock->vtable->destroy(lock); + } + + void Lock() + { + if (lock) + { + InterlockedExchangeAdd(&lock->use_count_, 1); + } + } +}; \ No newline at end of file diff --git a/include/global.h b/include/global.h index eff5d78..c0c27eb 100644 --- a/include/global.h +++ b/include/global.h @@ -161,6 +161,19 @@ struct Result { inline bool IsFail() { return reason != nullptr; } }; +bool InterlockedExchangeAdd(volatile unsigned *addr, unsigned value) +{ + bool _result; + asm( + "lock xadd [eax], edx;" + "setnz al;" + : "=a"(_result) + : "a"(addr), + "d"(value) + :); + return _result; +} + template T Offset(void *ptr, size_t offset) {