mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-07 07:25:26 +00:00
Moved Rc, BitSet, LinkedNode, IdMap utilities from orbis to rx
This commit is contained in:
parent
7b03b695f5
commit
ac853e0817
102 changed files with 1755 additions and 441 deletions
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
#include "orbis-config.hpp"
|
||||
#include "rx/SharedMutex.hpp"
|
||||
#include "utils/BitSet.hpp"
|
||||
#include "utils/Rc.hpp"
|
||||
#include "rx/BitSet.hpp"
|
||||
#include "rx/Rc.hpp"
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
|
|
@ -44,7 +44,7 @@ static_assert(sizeof(BudgetInfo) == 0x18);
|
|||
using BudgetInfoList =
|
||||
std::array<BudgetInfo, static_cast<int>(BudgetResource::_count)>;
|
||||
|
||||
class Budget : public RcBase {
|
||||
class Budget : public rx::RcBase {
|
||||
using BudgetList =
|
||||
std::array<BudgetItem, static_cast<int>(BudgetResource::_count)>;
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ public:
|
|||
|
||||
private:
|
||||
mutable rx::shared_mutex mMtx;
|
||||
orbis::BitSet<static_cast<int>(BudgetResource::_count)> mUsed;
|
||||
rx::BitSet<static_cast<int>(BudgetResource::_count)> mUsed;
|
||||
ProcessType mProcessType{};
|
||||
BudgetList mList;
|
||||
char mName[32]{};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "utils/Rc.hpp"
|
||||
#include "rx/Rc.hpp"
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
|
@ -56,22 +56,30 @@ using kunmap =
|
|||
template <typename T, typename... Args>
|
||||
requires(std::is_constructible_v<T, Args...>)
|
||||
T *knew(Args &&...args) {
|
||||
auto loc = static_cast<T *>(utils::kalloc(sizeof(T), alignof(T)));
|
||||
auto res = std::construct_at(loc, std::forward<Args>(args)...);
|
||||
if constexpr (requires(T *t) { t->_total_size = sizeof(T); })
|
||||
res->_total_size = sizeof(T);
|
||||
return res;
|
||||
if constexpr (std::is_base_of_v<rx::RcBase, T>) {
|
||||
static_assert(!std::is_final_v<T>);
|
||||
struct DynamicObject final : T {
|
||||
using T::T;
|
||||
|
||||
void operator delete(void *pointer) { utils::kfree(pointer, sizeof(T)); }
|
||||
};
|
||||
|
||||
auto loc = static_cast<DynamicObject *>(
|
||||
utils::kalloc(sizeof(DynamicObject), alignof(DynamicObject)));
|
||||
return std::construct_at(loc, std::forward<Args>(args)...);
|
||||
} else {
|
||||
static_assert(!std::is_polymorphic_v<T>, "Polymorphic type should be derived from rx::RcBase");
|
||||
|
||||
auto loc = static_cast<T *>(utils::kalloc(sizeof(T), alignof(T)));
|
||||
return std::construct_at(loc, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <typename T> void kdelete(T *ptr) {
|
||||
auto total_size = sizeof(T);
|
||||
if constexpr (requires(T *t) { t->_total_size = sizeof(T); })
|
||||
total_size = ptr->_total_size;
|
||||
else
|
||||
static_assert(std::is_final_v<T>, "Uncertain type size");
|
||||
static_assert(std::is_final_v<T>, "Uncertain type size");
|
||||
ptr->~T();
|
||||
utils::kfree(ptr, total_size);
|
||||
utils::kfree(ptr, sizeof(T));
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
#include "rx/SharedCV.hpp"
|
||||
#include "rx/SharedMutex.hpp"
|
||||
#include "thread/types.hpp"
|
||||
#include "utils/IdMap.hpp"
|
||||
#include "utils/LinkedNode.hpp"
|
||||
#include "rx/IdMap.hpp"
|
||||
#include "rx/LinkedNode.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
|
|
@ -57,7 +57,7 @@ enum class FwType : std::uint8_t {
|
|||
Ps5,
|
||||
};
|
||||
|
||||
struct RcAppInfo : RcBase, AppInfoEx {
|
||||
struct RcAppInfo : rx::RcBase, AppInfoEx {
|
||||
orbis::uint32_t appState = 0;
|
||||
};
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ public:
|
|||
Process *findProcessById(pid_t pid) const;
|
||||
Process *findProcessByHostId(std::uint64_t pid) const;
|
||||
|
||||
utils::LinkedNode<Process> *getProcessList() { return m_processes; }
|
||||
rx::LinkedNode<Process> *getProcessList() { return m_processes; }
|
||||
|
||||
long allocatePid() {
|
||||
std::lock_guard lock(m_thread_id_mtx);
|
||||
|
|
@ -98,7 +98,7 @@ public:
|
|||
return {it->second.get(), inserted};
|
||||
}
|
||||
|
||||
Ref<EventFlag> findEventFlag(std::string_view name) {
|
||||
rx::Ref<EventFlag> findEventFlag(std::string_view name) {
|
||||
std::lock_guard lock(m_evf_mtx);
|
||||
|
||||
if (auto it = m_event_flags.find(name); it != m_event_flags.end()) {
|
||||
|
|
@ -121,7 +121,7 @@ public:
|
|||
return {it->second.get(), inserted};
|
||||
}
|
||||
|
||||
Ref<Semaphore> findSemaphore(std::string_view name) {
|
||||
rx::Ref<Semaphore> findSemaphore(std::string_view name) {
|
||||
std::lock_guard lock(m_sem_mtx);
|
||||
if (auto it = m_semaphores.find(name); it != m_semaphores.end()) {
|
||||
return it->second;
|
||||
|
|
@ -130,7 +130,7 @@ public:
|
|||
return {};
|
||||
}
|
||||
|
||||
std::pair<Ref<IpmiServer>, ErrorCode> createIpmiServer(utils::kstring name) {
|
||||
std::pair<rx::Ref<IpmiServer>, ErrorCode> createIpmiServer(utils::kstring name) {
|
||||
std::lock_guard lock(m_sem_mtx);
|
||||
auto [it, inserted] = mIpmiServers.try_emplace(std::move(name), nullptr);
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ public:
|
|||
return {it->second, {}};
|
||||
}
|
||||
|
||||
Ref<IpmiServer> findIpmiServer(std::string_view name) {
|
||||
rx::Ref<IpmiServer> findIpmiServer(std::string_view name) {
|
||||
std::lock_guard lock(m_sem_mtx);
|
||||
if (auto it = mIpmiServers.find(name); it != mIpmiServers.end()) {
|
||||
return it->second;
|
||||
|
|
@ -191,20 +191,20 @@ public:
|
|||
return getUmtxChainIndexed(1, t, flags, ptr);
|
||||
}
|
||||
|
||||
Ref<EventEmitter> deviceEventEmitter;
|
||||
Ref<RcBase> shmDevice;
|
||||
Ref<RcBase> dmemDevice;
|
||||
Ref<RcBase> blockpoolDevice;
|
||||
Ref<RcBase> gpuDevice;
|
||||
Ref<RcBase> dceDevice;
|
||||
rx::Ref<EventEmitter> deviceEventEmitter;
|
||||
rx::Ref<rx::RcBase> shmDevice;
|
||||
rx::Ref<rx::RcBase> dmemDevice;
|
||||
rx::Ref<rx::RcBase> blockpoolDevice;
|
||||
rx::Ref<rx::RcBase> gpuDevice;
|
||||
rx::Ref<rx::RcBase> dceDevice;
|
||||
rx::shared_mutex gpuDeviceMtx;
|
||||
uint sdkVersion{};
|
||||
uint fwSdkVersion{};
|
||||
uint safeMode{};
|
||||
utils::RcIdMap<RcBase, sint, 4097, 1> ipmiMap;
|
||||
RcIdMap<RcAppInfo> appInfos;
|
||||
RcIdMap<Budget, sint, 4097, 1> budgets;
|
||||
Ref<Budget> processTypeBudgets[4];
|
||||
rx::RcIdMap<rx::RcBase, sint, 4097, 1> ipmiMap;
|
||||
rx::RcIdMap<RcAppInfo> appInfos;
|
||||
rx::RcIdMap<Budget, sint, 4097, 1> budgets;
|
||||
rx::Ref<Budget> processTypeBudgets[4];
|
||||
|
||||
rx::shared_mutex regMgrMtx;
|
||||
kmap<std::uint32_t, std::uint32_t> regMgrInt;
|
||||
|
|
@ -213,7 +213,7 @@ public:
|
|||
FwType fwType = FwType::Unknown;
|
||||
bool isDevKit = false;
|
||||
|
||||
Ref<Budget> createProcessTypeBudget(Budget::ProcessType processType,
|
||||
rx::Ref<Budget> createProcessTypeBudget(Budget::ProcessType processType,
|
||||
std::string_view name,
|
||||
std::span<const BudgetInfo> items) {
|
||||
auto budget = orbis::knew<orbis::Budget>(name, processType, items);
|
||||
|
|
@ -222,7 +222,7 @@ public:
|
|||
return budget;
|
||||
}
|
||||
|
||||
Ref<Budget> getProcessTypeBudget(Budget::ProcessType processType) {
|
||||
rx::Ref<Budget> getProcessTypeBudget(Budget::ProcessType processType) {
|
||||
return processTypeBudgets[static_cast<int>(processType)];
|
||||
}
|
||||
|
||||
|
|
@ -239,18 +239,18 @@ private:
|
|||
std::atomic<long> m_tsc_freq{0};
|
||||
|
||||
rx::shared_mutex m_thread_id_mtx;
|
||||
OwningIdMap<char, long, 256, 0> m_thread_id_map;
|
||||
rx::OwningIdMap<char, long, 256, 0> m_thread_id_map;
|
||||
mutable rx::shared_mutex m_proc_mtx;
|
||||
utils::LinkedNode<Process> *m_processes = nullptr;
|
||||
rx::LinkedNode<Process> *m_processes = nullptr;
|
||||
|
||||
rx::shared_mutex m_evf_mtx;
|
||||
utils::kmap<utils::kstring, Ref<EventFlag>> m_event_flags;
|
||||
utils::kmap<utils::kstring, rx::Ref<EventFlag>> m_event_flags;
|
||||
|
||||
rx::shared_mutex m_sem_mtx;
|
||||
utils::kmap<utils::kstring, Ref<Semaphore>> m_semaphores;
|
||||
utils::kmap<utils::kstring, rx::Ref<Semaphore>> m_semaphores;
|
||||
|
||||
rx::shared_mutex mIpmiServerMtx;
|
||||
utils::kmap<utils::kstring, Ref<IpmiServer>> mIpmiServers;
|
||||
utils::kmap<utils::kstring, rx::Ref<IpmiServer>> mIpmiServers;
|
||||
|
||||
rx::shared_mutex m_kenv_mtx;
|
||||
utils::kmap<utils::kstring, char[128]> m_kenv; // max size: 127 + '\0'
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "KernelAllocator.hpp"
|
||||
#include "thread/Thread.hpp"
|
||||
#include "rx/SharedMutex.hpp"
|
||||
#include "thread/Thread.hpp"
|
||||
#include <atomic>
|
||||
|
||||
namespace orbis {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include "note.hpp"
|
||||
#include "rx/SharedMutex.hpp"
|
||||
#include "stat.hpp"
|
||||
#include "utils/Rc.hpp"
|
||||
#include "rx/Rc.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
namespace orbis {
|
||||
|
|
@ -73,11 +73,11 @@ struct FileOps {
|
|||
Thread *thread) = nullptr;
|
||||
};
|
||||
|
||||
struct File : RcBase {
|
||||
struct File : rx::RcBase {
|
||||
rx::shared_mutex mtx;
|
||||
Ref<EventEmitter> event;
|
||||
rx::Ref<EventEmitter> event;
|
||||
const FileOps *ops = nullptr;
|
||||
Ref<RcBase> device;
|
||||
rx::Ref<RcBase> device;
|
||||
std::uint64_t nextOff = 0;
|
||||
int flags = 0;
|
||||
int mode = 0;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include "orbis-config.hpp"
|
||||
#include "rx/SharedCV.hpp"
|
||||
#include "rx/SharedMutex.hpp"
|
||||
#include "utils/Rc.hpp"
|
||||
#include "rx/Rc.hpp"
|
||||
#include <list>
|
||||
#include <optional>
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ struct IpmiSession;
|
|||
struct IpmiClient;
|
||||
struct Thread;
|
||||
|
||||
struct IpmiServer : RcBase {
|
||||
struct IpmiServer : rx::RcBase {
|
||||
struct IpmiPacketInfo {
|
||||
ulong inputSize;
|
||||
uint type;
|
||||
|
|
@ -27,12 +27,12 @@ struct IpmiServer : RcBase {
|
|||
struct Packet {
|
||||
IpmiPacketInfo info;
|
||||
lwpid_t clientTid;
|
||||
Ref<IpmiSession> session;
|
||||
rx::Ref<IpmiSession> session;
|
||||
kvector<std::byte> message;
|
||||
};
|
||||
|
||||
struct ConnectionRequest {
|
||||
Ref<IpmiClient> client;
|
||||
rx::Ref<IpmiClient> client;
|
||||
slong clientTid{};
|
||||
slong clientPid{};
|
||||
slong serverTid{};
|
||||
|
|
@ -53,7 +53,7 @@ struct IpmiServer : RcBase {
|
|||
explicit IpmiServer(kstring name) : name(std::move(name)) {}
|
||||
};
|
||||
|
||||
struct IpmiClient : RcBase {
|
||||
struct IpmiClient : rx::RcBase {
|
||||
struct MessageQueue {
|
||||
rx::shared_cv messageCv;
|
||||
kdeque<kvector<std::byte>> messages;
|
||||
|
|
@ -68,7 +68,7 @@ struct IpmiClient : RcBase {
|
|||
kstring name;
|
||||
ptr<void> clientImpl;
|
||||
ptr<void> userData;
|
||||
Ref<IpmiSession> session;
|
||||
rx::Ref<IpmiSession> session;
|
||||
rx::shared_mutex mutex;
|
||||
rx::shared_cv sessionCv;
|
||||
rx::shared_cv asyncResponseCv;
|
||||
|
|
@ -82,7 +82,7 @@ struct IpmiClient : RcBase {
|
|||
explicit IpmiClient(kstring name) : name(std::move(name)) {}
|
||||
};
|
||||
|
||||
struct IpmiSession : RcBase {
|
||||
struct IpmiSession : rx::RcBase {
|
||||
struct SyncResponse {
|
||||
sint errorCode;
|
||||
std::uint32_t callerTid;
|
||||
|
|
@ -91,8 +91,8 @@ struct IpmiSession : RcBase {
|
|||
|
||||
ptr<void> sessionImpl;
|
||||
ptr<void> userData;
|
||||
Ref<IpmiClient> client;
|
||||
Ref<IpmiServer> server;
|
||||
rx::Ref<IpmiClient> client;
|
||||
rx::Ref<IpmiServer> server;
|
||||
rx::shared_mutex mutex;
|
||||
rx::shared_cv responseCv;
|
||||
kdeque<SyncResponse> syncResponses;
|
||||
|
|
@ -185,12 +185,12 @@ static_assert(sizeof(IpmiClientConnectParams) == 0x20);
|
|||
|
||||
ErrorCode ipmiCreateClient(Process *proc, void *clientImpl, const char *name,
|
||||
const IpmiCreateClientConfig &config,
|
||||
Ref<IpmiClient> &result);
|
||||
rx::Ref<IpmiClient> &result);
|
||||
ErrorCode ipmiCreateServer(Process *proc, void *serverImpl, const char *name,
|
||||
const IpmiCreateServerConfig &config,
|
||||
Ref<IpmiServer> &result);
|
||||
rx::Ref<IpmiServer> &result);
|
||||
ErrorCode ipmiCreateSession(Thread *thread, void *sessionImpl,
|
||||
ptr<void> userData, Ref<IpmiSession> &result);
|
||||
ptr<void> userData, rx::Ref<IpmiSession> &result);
|
||||
|
||||
SysResult sysIpmiCreateClient(Thread *thread, ptr<uint> result,
|
||||
ptr<void> params, uint64_t paramsSz);
|
||||
|
|
|
|||
|
|
@ -4,12 +4,10 @@
|
|||
#include "ModuleSegment.hpp"
|
||||
|
||||
#include "../KernelAllocator.hpp"
|
||||
#include "../utils/Rc.hpp"
|
||||
#include "rx/Rc.hpp"
|
||||
|
||||
#include "orbis-config.hpp"
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace orbis {
|
||||
struct Thread;
|
||||
|
|
@ -118,16 +116,13 @@ struct Module final {
|
|||
utils::kvector<Relocation> nonPltRelocations;
|
||||
utils::kvector<ModuleNeeded> neededModules;
|
||||
utils::kvector<ModuleNeeded> neededLibraries;
|
||||
utils::kvector<utils::Ref<Module>> importedModules;
|
||||
utils::kvector<utils::Ref<Module>> namespaceModules;
|
||||
utils::kvector<rx::Ref<Module>> importedModules;
|
||||
utils::kvector<rx::Ref<Module>> namespaceModules;
|
||||
utils::kvector<utils::kstring> needed;
|
||||
|
||||
std::atomic<unsigned> references{0};
|
||||
unsigned _total_size = 0;
|
||||
|
||||
void incRef() {
|
||||
if (_total_size != sizeof(Module))
|
||||
std::abort();
|
||||
if (references.fetch_add(1, std::memory_order::relaxed) > 512) {
|
||||
assert(!"too many references");
|
||||
}
|
||||
|
|
@ -142,10 +137,11 @@ struct Module final {
|
|||
|
||||
orbis::SysResult relocate(Process *process);
|
||||
|
||||
void operator delete(void *pointer);
|
||||
|
||||
private:
|
||||
void destroy();
|
||||
};
|
||||
|
||||
utils::Ref<Module> createModule(Thread *p, std::string vfsPath,
|
||||
const char *name);
|
||||
rx::Ref<Module> createModule(Thread *p, std::string vfsPath, const char *name);
|
||||
} // namespace orbis
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include "KernelAllocator.hpp"
|
||||
#include "orbis-config.hpp"
|
||||
#include "orbis/utils/Rc.hpp"
|
||||
#include "rx/Rc.hpp"
|
||||
#include "rx/SharedMutex.hpp"
|
||||
#include <limits>
|
||||
#include <set>
|
||||
|
|
@ -77,17 +77,17 @@ struct KQueue;
|
|||
struct KNote {
|
||||
rx::shared_mutex mutex;
|
||||
KQueue *queue;
|
||||
Ref<File> file;
|
||||
rx::Ref<File> file;
|
||||
KEvent event{};
|
||||
bool enabled = true;
|
||||
bool triggered = false;
|
||||
void *linked = nullptr; // TODO: use Ref<>
|
||||
kvector<Ref<EventEmitter>> emitters;
|
||||
void *linked = nullptr; // TODO: use rx::Ref<>
|
||||
kvector<rx::Ref<EventEmitter>> emitters;
|
||||
|
||||
~KNote();
|
||||
};
|
||||
|
||||
struct EventEmitter : orbis::RcBase {
|
||||
struct EventEmitter : rx::RcBase {
|
||||
rx::shared_mutex mutex;
|
||||
std::set<KNote *, std::less<>, kallocator<KNote *>> notes;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@
|
|||
#include "file.hpp"
|
||||
#include "rx/SharedCV.hpp"
|
||||
#include "rx/SharedMutex.hpp"
|
||||
#include "utils/Rc.hpp"
|
||||
#include "rx/Rc.hpp"
|
||||
#include <utility>
|
||||
|
||||
namespace orbis {
|
||||
struct Pipe final : File {
|
||||
struct Pipe : File {
|
||||
rx::shared_cv cv;
|
||||
kvector<std::byte> data;
|
||||
Ref<Pipe> other;
|
||||
rx::Ref<Pipe> other;
|
||||
};
|
||||
|
||||
std::pair<Ref<Pipe>, Ref<Pipe>> createPipe();
|
||||
std::pair<rx::Ref<Pipe>, rx::Ref<Pipe>> createPipe();
|
||||
} // namespace orbis
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
#include "orbis/Budget.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/module/Module.hpp"
|
||||
#include "orbis/utils/IdMap.hpp"
|
||||
#include "rx/IdMap.hpp"
|
||||
#include "rx/SharedMutex.hpp"
|
||||
#include <optional>
|
||||
|
||||
|
|
@ -85,16 +85,16 @@ struct Process final {
|
|||
std::uint64_t nextTlsSlot = 1;
|
||||
std::uint64_t lastTlsOffset = 0;
|
||||
|
||||
utils::RcIdMap<EventFlag, sint, 4097, 1> evfMap;
|
||||
utils::RcIdMap<Semaphore, sint, 4097, 1> semMap;
|
||||
utils::RcIdMap<Module, ModuleHandle> modulesMap;
|
||||
utils::OwningIdMap<Thread, lwpid_t> threadsMap;
|
||||
utils::RcIdMap<orbis::File, sint> fileDescriptors;
|
||||
rx::RcIdMap<EventFlag, sint, 4097, 1> evfMap;
|
||||
rx::RcIdMap<Semaphore, sint, 4097, 1> semMap;
|
||||
rx::RcIdMap<Module, ModuleHandle> modulesMap;
|
||||
rx::OwningIdMap<Thread, lwpid_t> threadsMap;
|
||||
rx::RcIdMap<orbis::File, sint> fileDescriptors;
|
||||
|
||||
// Named objects for debugging
|
||||
rx::shared_mutex namedObjMutex;
|
||||
utils::kmap<void *, utils::kstring> namedObjNames;
|
||||
utils::OwningIdMap<NamedObjInfo, uint, 65535, 1> namedObjIds;
|
||||
rx::OwningIdMap<NamedObjInfo, uint, 65535, 1> namedObjIds;
|
||||
|
||||
utils::kmap<std::int32_t, SigAction> sigActions;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "../module/ModuleHandle.hpp"
|
||||
#include "../thread/types.hpp"
|
||||
#include "orbis-config.hpp"
|
||||
#include "orbis/utils/Rc.hpp"
|
||||
#include "rx/Rc.hpp"
|
||||
|
||||
namespace orbis {
|
||||
struct Thread;
|
||||
|
|
@ -39,21 +39,21 @@ struct ProcessOps {
|
|||
ptr<MemoryProtection> protection);
|
||||
|
||||
SysResult (*open)(Thread *thread, ptr<const char> path, sint flags, sint mode,
|
||||
Ref<File> *file);
|
||||
rx::Ref<File> *file);
|
||||
SysResult (*shm_open)(Thread *thread, const char *path, sint flags, sint mode,
|
||||
Ref<File> *file);
|
||||
rx::Ref<File> *file);
|
||||
SysResult (*unlink)(Thread *thread, ptr<const char> path);
|
||||
SysResult (*mkdir)(Thread *thread, ptr<const char> path, sint mode);
|
||||
SysResult (*rmdir)(Thread *thread, ptr<const char> path);
|
||||
SysResult (*rename)(Thread *thread, ptr<const char> from, ptr<const char> to);
|
||||
SysResult (*blockpool_open)(Thread *thread, Ref<File> *file);
|
||||
SysResult (*blockpool_open)(Thread *thread, rx::Ref<File> *file);
|
||||
SysResult (*blockpool_map)(Thread *thread, caddr_t addr, size_t len,
|
||||
sint prot, sint flags);
|
||||
SysResult (*blockpool_unmap)(Thread *thread, caddr_t addr, size_t len);
|
||||
SysResult (*socket)(Thread *thread, ptr<const char> name, sint domain,
|
||||
sint type, sint protocol, Ref<File> *file);
|
||||
sint type, sint protocol, rx::Ref<File> *file);
|
||||
SysResult (*socketpair)(Thread *thread, sint domain, sint type, sint protocol,
|
||||
Ref<File> *a, Ref<File> *b);
|
||||
rx::Ref<File> *a, rx::Ref<File> *b);
|
||||
SysResult (*shm_unlink)(Thread *thread, const char *path);
|
||||
SysResult (*dynlib_get_obj_member)(Thread *thread, ModuleHandle handle,
|
||||
uint64_t index, ptr<ptr<void>> addrp);
|
||||
|
|
|
|||
|
|
@ -1,74 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
namespace orbis {
|
||||
inline namespace utils {
|
||||
// Atomic operation; returns old value, or pair of old value and return value
|
||||
// (cancel op if evaluates to false)
|
||||
template <typename T, typename F, typename RT = std::invoke_result_t<F, T &>>
|
||||
inline std::conditional_t<std::is_void_v<RT>, T, std::pair<T, RT>>
|
||||
atomic_fetch_op(std::atomic<T> &v, F func) {
|
||||
T _new, old = v.load();
|
||||
while (true) {
|
||||
_new = old;
|
||||
if constexpr (std::is_void_v<RT>) {
|
||||
std::invoke(func, _new);
|
||||
if (v.compare_exchange_strong(old, _new)) [[likely]] {
|
||||
return old;
|
||||
}
|
||||
} else {
|
||||
RT ret = std::invoke(func, _new);
|
||||
if (!ret || v.compare_exchange_strong(old, _new)) [[likely]] {
|
||||
return {old, std::move(ret)};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Atomic operation; returns function result value, function is the lambda
|
||||
template <typename T, typename F, typename RT = std::invoke_result_t<F, T &>>
|
||||
inline RT atomic_op(std::atomic<T> &v, F func) {
|
||||
T _new, old = v.load();
|
||||
while (true) {
|
||||
_new = old;
|
||||
if constexpr (std::is_void_v<RT>) {
|
||||
std::invoke(func, _new);
|
||||
if (v.compare_exchange_strong(old, _new)) [[likely]] {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
RT result = std::invoke(func, _new);
|
||||
if (v.compare_exchange_strong(old, _new)) [[likely]] {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__ATOMIC_HLE_ACQUIRE) && defined(__ATOMIC_HLE_RELEASE)
|
||||
static constexpr int s_hle_ack = __ATOMIC_SEQ_CST | __ATOMIC_HLE_ACQUIRE;
|
||||
static constexpr int s_hle_rel = __ATOMIC_SEQ_CST | __ATOMIC_HLE_RELEASE;
|
||||
#else
|
||||
static constexpr int s_hle_ack = __ATOMIC_SEQ_CST;
|
||||
static constexpr int s_hle_rel = __ATOMIC_SEQ_CST;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
inline bool compare_exchange_hle_acq(std::atomic<T> &dest, T &comp, T exch) {
|
||||
static_assert(sizeof(T) == 4 || sizeof(T) == 8);
|
||||
static_assert(std::atomic<T>::is_always_lock_free);
|
||||
return __atomic_compare_exchange(reinterpret_cast<T *>(&dest), &comp, &exch,
|
||||
false, s_hle_ack, s_hle_ack);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T fetch_add_hle_rel(std::atomic<T> &dest, T value) {
|
||||
static_assert(sizeof(T) == 4 || sizeof(T) == 8);
|
||||
static_assert(std::atomic<T>::is_always_lock_free);
|
||||
return __atomic_fetch_add(reinterpret_cast<T *>(&dest), value, s_hle_rel);
|
||||
}
|
||||
} // namespace utils
|
||||
} // namespace orbis
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
#pragma once
|
||||
#include <bit>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace orbis {
|
||||
inline namespace utils {
|
||||
template <std::size_t Count> struct BitSet {
|
||||
using chunk_type = std::uint64_t;
|
||||
static constexpr auto BitsPerChunk = sizeof(chunk_type) * 8;
|
||||
static constexpr auto ChunkCount = (Count + BitsPerChunk - 1) / BitsPerChunk;
|
||||
chunk_type _bits[ChunkCount]{};
|
||||
|
||||
struct iterator_end {};
|
||||
|
||||
struct iterator {
|
||||
iterator() = default;
|
||||
|
||||
constexpr iterator &operator++() {
|
||||
offset = bitSet->countr_zero(offset + 1);
|
||||
return *this;
|
||||
}
|
||||
constexpr bool operator==(const iterator_end &) const {
|
||||
return offset >= Count;
|
||||
}
|
||||
constexpr std::size_t operator*() const { return offset; }
|
||||
|
||||
private:
|
||||
constexpr iterator(const BitSet *bitSet)
|
||||
: bitSet(bitSet), offset(bitSet->countr_zero()) {}
|
||||
|
||||
const BitSet *bitSet = nullptr;
|
||||
std::size_t offset = 0;
|
||||
|
||||
friend BitSet;
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr std::size_t countr_one() const {
|
||||
std::size_t result = 0;
|
||||
for (auto bits : _bits) {
|
||||
auto count = std::countr_one(bits);
|
||||
result += count;
|
||||
|
||||
if (count != BitsPerChunk) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t popcount() const {
|
||||
std::size_t result = 0;
|
||||
|
||||
for (auto bits : _bits) {
|
||||
result += std::popcount(bits);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t
|
||||
countr_zero(std::size_t offset = 0) const {
|
||||
std::size_t result = 0;
|
||||
|
||||
if (auto chunkOffset = offset % BitsPerChunk) {
|
||||
auto count =
|
||||
std::countr_zero(_bits[offset / BitsPerChunk] >> chunkOffset);
|
||||
|
||||
if (count != BitsPerChunk) {
|
||||
return count + offset;
|
||||
}
|
||||
|
||||
offset = (offset + BitsPerChunk - 1) & ~(BitsPerChunk - 1);
|
||||
}
|
||||
|
||||
for (auto i = offset / BitsPerChunk; i < ChunkCount; ++i) {
|
||||
auto count = std::countr_zero(_bits[i]);
|
||||
result += count;
|
||||
|
||||
if (count != BitsPerChunk) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result + offset;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool empty() const {
|
||||
for (auto bits : _bits) {
|
||||
if (bits != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool full() const {
|
||||
if constexpr (Count < BitsPerChunk) {
|
||||
return _bits[0] == (static_cast<std::uint64_t>(1) << Count) - 1;
|
||||
}
|
||||
|
||||
for (auto bits : _bits) {
|
||||
if (bits != ~static_cast<chunk_type>(0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr void clear(std::size_t index) {
|
||||
_bits[index / BitsPerChunk] &=
|
||||
~(static_cast<chunk_type>(1) << (index % BitsPerChunk));
|
||||
}
|
||||
|
||||
constexpr void set(std::size_t index) {
|
||||
_bits[index / BitsPerChunk] |= static_cast<chunk_type>(1)
|
||||
<< (index % BitsPerChunk);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool test(std::size_t index) const {
|
||||
return (_bits[index / BitsPerChunk] &
|
||||
(static_cast<chunk_type>(1) << (index % BitsPerChunk))) != 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr iterator begin() const { return iterator(this); }
|
||||
[[nodiscard]] constexpr iterator_end end() const { return {}; }
|
||||
};
|
||||
} // namespace utils
|
||||
} // namespace orbis
|
||||
|
|
@ -1,408 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "BitSet.hpp"
|
||||
#include "Rc.hpp"
|
||||
#include "rx/SharedMutex.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
namespace orbis {
|
||||
inline namespace utils {
|
||||
template <WithRc T, typename IdT = int, std::size_t MaxId = 4096,
|
||||
std::size_t MinId = 0>
|
||||
requires(MaxId > MinId)
|
||||
class RcIdMap {
|
||||
static constexpr auto ChunkSize = std::min<std::size_t>(MaxId - MinId, 64);
|
||||
static constexpr auto ChunkCount =
|
||||
(MaxId - MinId + ChunkSize - 1) / ChunkSize;
|
||||
|
||||
struct IdMapChunk {
|
||||
BitSet<ChunkSize> mask = {};
|
||||
T *objects[ChunkSize]{};
|
||||
|
||||
~IdMapChunk() {
|
||||
std::size_t index = mask.countr_zero();
|
||||
|
||||
while (index < ChunkSize) {
|
||||
objects[index]->decRef();
|
||||
index = mask.countr_zero(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool insert(std::size_t index, T *object) {
|
||||
if (mask.test(index)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mask.set(index);
|
||||
objects[index] = object;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t insert(T *object) {
|
||||
std::size_t index = mask.countr_one();
|
||||
mask.set(index);
|
||||
objects[index] = object;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
T *get(std::size_t index) const { return objects[index]; }
|
||||
|
||||
void remove(std::size_t index) {
|
||||
objects[index]->decRef();
|
||||
objects[index] = nullptr;
|
||||
mask.clear(index);
|
||||
}
|
||||
};
|
||||
|
||||
IdMapChunk m_chunks[ChunkCount]{};
|
||||
BitSet<ChunkCount> m_fullChunks;
|
||||
|
||||
public:
|
||||
static constexpr auto npos = static_cast<IdT>(~static_cast<std::size_t>(0));
|
||||
|
||||
mutable rx::shared_mutex mutex;
|
||||
|
||||
struct end_iterator {};
|
||||
|
||||
class iterator {
|
||||
const IdMapChunk *chunks = nullptr;
|
||||
std::size_t chunk = 0;
|
||||
std::size_t index = 0;
|
||||
|
||||
public:
|
||||
iterator(const IdMapChunk *chunks) : chunks(chunks) { findNext(); }
|
||||
|
||||
iterator &operator++() {
|
||||
++index;
|
||||
findNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::pair<IdT, T *> operator*() const {
|
||||
return {static_cast<IdT>(chunk * ChunkSize + index + MinId),
|
||||
chunks[chunk].objects[index]};
|
||||
}
|
||||
|
||||
bool operator!=(const end_iterator &) const { return chunk < ChunkCount; }
|
||||
bool operator==(const end_iterator &) const { return chunk >= ChunkCount; }
|
||||
|
||||
private:
|
||||
void findNext() {
|
||||
while (chunk < ChunkCount) {
|
||||
index = chunks[chunk].mask.countr_zero(index);
|
||||
|
||||
if (index < ChunkSize) {
|
||||
break;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
chunk++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void walk(auto cb) {
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
for (std::size_t chunk = 0; chunk < ChunkCount; ++chunk) {
|
||||
std::size_t index = m_chunks[chunk].mask.countr_zero();
|
||||
|
||||
while (index < ChunkSize) {
|
||||
cb(static_cast<IdT>(index + chunk * ChunkSize + MinId),
|
||||
m_chunks[chunk].objects[index]);
|
||||
|
||||
index = m_chunks[chunk].mask.countr_zero(index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iterator begin() const { return iterator{m_chunks}; }
|
||||
|
||||
end_iterator end() const { return {}; }
|
||||
|
||||
private:
|
||||
bool insert_impl(IdT id, T *object) {
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
auto raw = static_cast<std::size_t>(id);
|
||||
auto page = (raw - MinId) / ChunkSize;
|
||||
auto index = (raw - MinId) % ChunkSize;
|
||||
|
||||
if (page >= ChunkCount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_chunks[page].insert(index, object)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_chunks[page].mask.full()) {
|
||||
m_fullChunks.set(page);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IdT insert_impl(T *object) {
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
auto page = m_fullChunks.countr_one();
|
||||
|
||||
if (page == ChunkCount) {
|
||||
return npos;
|
||||
}
|
||||
|
||||
auto index = m_chunks[page].insert(object);
|
||||
|
||||
if (m_chunks[page].mask.full()) {
|
||||
m_fullChunks.set(page);
|
||||
}
|
||||
|
||||
return {static_cast<IdT>(page * ChunkSize + index + MinId)};
|
||||
}
|
||||
|
||||
public:
|
||||
IdT insert(T *object) {
|
||||
auto result = insert_impl(object);
|
||||
|
||||
if (result != npos) {
|
||||
object->incRef();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
IdT insert(const Ref<T> &ref) { return insert(ref.get()); }
|
||||
|
||||
IdT insert(Ref<T> &&ref) {
|
||||
auto object = ref.release();
|
||||
auto result = insert_impl(object);
|
||||
|
||||
if (result == npos) {
|
||||
object->decRef();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool insert(IdT id, T *object) {
|
||||
if (insert_impl(id, object)) {
|
||||
object->incRef();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool insert(IdT id, const Ref<T> &ref) { return insert(id, ref.get()); }
|
||||
|
||||
bool insert(IdT id, Ref<T> &&ref) {
|
||||
auto object = ref.release();
|
||||
|
||||
if (!insert_impl(id, object)) {
|
||||
object->decRef();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Ref<T> get(IdT id) const {
|
||||
const auto rawId = static_cast<std::size_t>(id) - MinId;
|
||||
|
||||
if (rawId >= MaxId - MinId) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto chunk = rawId / ChunkSize;
|
||||
const auto index = rawId % ChunkSize;
|
||||
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
if (!m_chunks[chunk].mask.test(index)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_chunks[chunk].get(index);
|
||||
}
|
||||
|
||||
bool destroy(IdT id)
|
||||
requires requires(T t) { t.destroy(); }
|
||||
{
|
||||
const auto rawId = static_cast<std::size_t>(id) - MinId;
|
||||
|
||||
if (rawId >= MaxId - MinId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto chunk = rawId / ChunkSize;
|
||||
const auto index = rawId % ChunkSize;
|
||||
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
if (!m_chunks[chunk].mask.test(index)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_chunks[chunk].get(index)->destroy();
|
||||
m_chunks[chunk].remove(index);
|
||||
m_fullChunks.clear(chunk);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool close(IdT id) {
|
||||
const auto rawId = static_cast<std::size_t>(id) - MinId;
|
||||
|
||||
if (rawId >= MaxId - MinId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto chunk = rawId / ChunkSize;
|
||||
const auto index = rawId % ChunkSize;
|
||||
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
if (!m_chunks[chunk].mask.test(index)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_chunks[chunk].remove(index);
|
||||
m_fullChunks.clear(chunk);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename IdT = int, std::size_t MaxId = 4096,
|
||||
std::size_t MinId = 0>
|
||||
requires(MaxId > MinId)
|
||||
struct OwningIdMap {
|
||||
static constexpr auto ChunkSize = std::min<std::size_t>(MaxId - MinId, 64);
|
||||
static constexpr auto ChunkCount =
|
||||
(MaxId - MinId + ChunkSize - 1) / ChunkSize;
|
||||
|
||||
struct IdMapChunk {
|
||||
BitSet<ChunkSize> mask = {};
|
||||
alignas(T) std::byte objects[sizeof(T) * ChunkSize];
|
||||
|
||||
~IdMapChunk() {
|
||||
std::size_t pageOffset = 0;
|
||||
|
||||
for (auto page : mask._bits) {
|
||||
auto tmp = page;
|
||||
|
||||
while (true) {
|
||||
const auto index = std::countr_zero(tmp);
|
||||
|
||||
if (index >= 64) {
|
||||
break;
|
||||
}
|
||||
|
||||
tmp &= ~(static_cast<std::uint64_t>(1) << index);
|
||||
destroy(pageOffset + index);
|
||||
}
|
||||
|
||||
pageOffset += 64;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... ArgsT>
|
||||
std::pair<std::size_t, T *> emplace_new(ArgsT &&...args) {
|
||||
std::size_t index = mask.countr_one();
|
||||
|
||||
if (index >= ChunkSize) {
|
||||
return {};
|
||||
}
|
||||
|
||||
mask.set(index);
|
||||
|
||||
return {index,
|
||||
std::construct_at(get(index), std::forward<ArgsT>(args)...)};
|
||||
}
|
||||
|
||||
T *get(std::size_t index) {
|
||||
return reinterpret_cast<T *>(objects + sizeof(T) * index);
|
||||
}
|
||||
|
||||
void destroy(std::size_t index) {
|
||||
std::destroy_at(get(index));
|
||||
mask.clear(index);
|
||||
}
|
||||
};
|
||||
|
||||
IdMapChunk chunks[ChunkCount]{};
|
||||
BitSet<ChunkCount> fullChunks;
|
||||
|
||||
template <typename... ArgsT>
|
||||
requires(std::is_constructible_v<T, ArgsT...>)
|
||||
std::pair<IdT, T *> emplace(ArgsT &&...args) {
|
||||
auto page = fullChunks.countr_one();
|
||||
|
||||
if (page == ChunkCount) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto newElem = chunks[page].emplace_new(std::forward<ArgsT>(args)...);
|
||||
|
||||
if (chunks[page].mask.full()) {
|
||||
fullChunks.set(page);
|
||||
}
|
||||
|
||||
return {static_cast<IdT>(page * ChunkSize + newElem.first + MinId),
|
||||
newElem.second};
|
||||
}
|
||||
|
||||
T *get(IdT id) {
|
||||
const auto rawId = static_cast<std::size_t>(id) - MinId;
|
||||
const auto chunk = rawId / ChunkSize;
|
||||
const auto index = rawId % ChunkSize;
|
||||
|
||||
if (chunk >= ChunkCount) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!chunks[chunk].mask.test(index)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return chunks[chunk].get(index);
|
||||
}
|
||||
|
||||
bool destroy(IdT id) {
|
||||
const auto rawId = static_cast<std::size_t>(id) - MinId;
|
||||
const auto chunk = rawId / ChunkSize;
|
||||
const auto index = rawId % ChunkSize;
|
||||
|
||||
if (chunk >= ChunkCount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!chunks[chunk].mask.test(index)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
chunks[chunk].destroy(index);
|
||||
fullChunks.clear(chunk);
|
||||
return true;
|
||||
}
|
||||
|
||||
void walk(auto cb) {
|
||||
for (std::size_t chunk = 0; chunk < ChunkCount; ++chunk) {
|
||||
std::size_t index = chunks[chunk].mask.countr_zero();
|
||||
|
||||
while (index < ChunkSize) {
|
||||
auto id = static_cast<IdT>(index + chunk * ChunkSize + MinId);
|
||||
cb(id, chunks[chunk].get(id));
|
||||
|
||||
index = chunks[chunk].mask.countr_zero(index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace utils
|
||||
} // namespace orbis
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace orbis {
|
||||
inline namespace utils {
|
||||
template <typename T> struct LinkedNode final {
|
||||
T object;
|
||||
LinkedNode *next = nullptr;
|
||||
LinkedNode *prev = nullptr;
|
||||
|
||||
void insertNext(LinkedNode &other) {
|
||||
other.next = next;
|
||||
other.prev = this;
|
||||
|
||||
if (next != nullptr) {
|
||||
next->prev = &other;
|
||||
}
|
||||
|
||||
next = &other;
|
||||
}
|
||||
|
||||
void insertPrev(LinkedNode &other) {
|
||||
other.next = this;
|
||||
other.prev = prev;
|
||||
|
||||
if (prev != nullptr) {
|
||||
prev->next = &other;
|
||||
}
|
||||
|
||||
prev = &other;
|
||||
}
|
||||
|
||||
LinkedNode *erase() {
|
||||
if (prev != nullptr) {
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
if (next != nullptr) {
|
||||
next->prev = prev;
|
||||
}
|
||||
|
||||
prev = nullptr;
|
||||
auto result = next;
|
||||
next = nullptr;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
} // namespace utils
|
||||
} // namespace orbis
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace orbis {
|
||||
// template <typename T, typename... Args> T *knew(Args &&...args);
|
||||
inline namespace utils {
|
||||
void kfree(void *ptr, std::size_t size);
|
||||
|
||||
struct RcBase {
|
||||
std::atomic<unsigned> references{0};
|
||||
unsigned _total_size = 0; // Set by knew/kcreate
|
||||
|
||||
virtual ~RcBase() = default;
|
||||
|
||||
void incRef() {
|
||||
if (!_total_size)
|
||||
std::abort();
|
||||
if (references.fetch_add(1, std::memory_order::relaxed) > 4096) {
|
||||
assert(!"too many references");
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if object was destroyed
|
||||
bool decRef() {
|
||||
if (references.fetch_sub(1, std::memory_order::relaxed) == 1) {
|
||||
auto size = _total_size;
|
||||
this->~RcBase();
|
||||
orbis::utils::kfree(this, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept WithRc = requires(T t) {
|
||||
t.incRef();
|
||||
t.decRef();
|
||||
};
|
||||
|
||||
template <typename T> class Ref {
|
||||
T *m_ref = nullptr;
|
||||
|
||||
public:
|
||||
Ref() = default;
|
||||
Ref(std::nullptr_t) noexcept {}
|
||||
|
||||
template <typename OT>
|
||||
requires(std::is_base_of_v<T, OT>)
|
||||
Ref(OT *ref) noexcept : m_ref(ref) {
|
||||
if (m_ref != nullptr) {
|
||||
ref->incRef();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename OT>
|
||||
requires(std::is_base_of_v<T, OT>)
|
||||
Ref(const Ref<OT> &other) noexcept : m_ref(other.get()) {
|
||||
if (m_ref != nullptr) {
|
||||
m_ref->incRef();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename OT>
|
||||
requires(std::is_base_of_v<T, OT>)
|
||||
Ref(Ref<OT> &&other) noexcept : m_ref(other.release()) {}
|
||||
|
||||
Ref(const Ref &other) noexcept : m_ref(other.get()) {
|
||||
if (m_ref != nullptr) {
|
||||
m_ref->incRef();
|
||||
}
|
||||
}
|
||||
Ref(Ref &&other) noexcept : m_ref(other.release()) {}
|
||||
|
||||
template <typename OT>
|
||||
requires(std::is_base_of_v<T, OT>)
|
||||
Ref &operator=(Ref<OT> &&other) noexcept {
|
||||
other.template cast<T>().swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename OT>
|
||||
requires(std::is_base_of_v<T, OT>)
|
||||
Ref &operator=(OT *other) noexcept {
|
||||
*this = Ref(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename OT>
|
||||
requires(std::is_base_of_v<T, OT>)
|
||||
Ref &operator=(const Ref<OT> &other) noexcept {
|
||||
*this = Ref(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Ref &operator=(const Ref &other) noexcept {
|
||||
*this = Ref(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Ref &operator=(Ref &&other) noexcept {
|
||||
other.swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Ref() {
|
||||
if (m_ref != nullptr) {
|
||||
m_ref->decRef();
|
||||
}
|
||||
}
|
||||
|
||||
void swap(Ref<T> &other) noexcept { std::swap(m_ref, other.m_ref); }
|
||||
T *get() const { return m_ref; }
|
||||
T *release() { return std::exchange(m_ref, nullptr); }
|
||||
T *operator->() const { return m_ref; }
|
||||
explicit operator bool() const { return m_ref != nullptr; }
|
||||
bool operator==(const Ref &) const = default;
|
||||
bool operator==(std::nullptr_t) const { return m_ref == nullptr; }
|
||||
auto operator<=>(const T *other) const { return m_ref <=> other; }
|
||||
auto operator<=>(const Ref &other) const = default;
|
||||
|
||||
template <typename OtherT> Ref<OtherT> cast() {
|
||||
return dynamic_cast<OtherT *>(m_ref);
|
||||
}
|
||||
template <typename OtherT> Ref<OtherT> staticCast() {
|
||||
return static_cast<OtherT *>(m_ref);
|
||||
}
|
||||
|
||||
template <typename OtherT> OtherT *rawCast() {
|
||||
return dynamic_cast<OtherT *>(m_ref);
|
||||
}
|
||||
template <typename OtherT> OtherT *rawStaticCast() {
|
||||
return static_cast<OtherT *>(m_ref);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> Ref(T *) -> Ref<T>;
|
||||
|
||||
// template <WithRc T, typename... ArgsT>
|
||||
// requires(std::is_constructible_v<T, ArgsT...>)
|
||||
// Ref<T> kcreate(ArgsT &&...args) {
|
||||
// return Ref<T>(knew<T>(std::forward<ArgsT>(args)...));
|
||||
// }
|
||||
} // namespace utils
|
||||
} // namespace orbis
|
||||
Loading…
Add table
Add a link
Reference in a new issue