Skip to content
LeviMC
English
AutoLightDark
LeviLamina
Loading...
Searching...
No Matches
InstancedThreadLocal.h
1#pragma once
2
3#include "mc/_HeaderOutputPredefine.h"
4
5#include "mc/deps/core/container/list.h"
6#include "mc/deps/core/threading/InstancedThreadLocalBase.h"
7#include "mc/platform/threading/TlsSlot.h"
8
9namespace Bedrock::Threading {
10
11template <typename T, typename Alloc = ::std::allocator<T>>
12class InstancedThreadLocal : public ::Bedrock::Threading::InstancedThreadLocalBase {
14 alignas(T)::std::byte mData[sizeof(T)];
15
16 [[nodiscard]] T* value() noexcept { return ::std::launder(reinterpret_cast<T*>(mData)); }
17 };
18
19 using ItemList = ::Bedrock::Intrusive::list<Item>;
20 using ItemAllocator = typename ::std::allocator_traits<Alloc>::template rebind_alloc<Item>;
21 using ItemTraits = ::std::allocator_traits<ItemAllocator>;
22
23public:
24 class IteratorType {
25 friend InstancedThreadLocal;
26
27 typename ItemList::iterator mIterator;
28
29 explicit IteratorType(typename ItemList::iterator iterator) noexcept : mIterator(iterator) {}
30
31 public:
32 [[nodiscard]] T& operator*() const noexcept { return *mIterator->value(); }
33 [[nodiscard]] T* operator->() const noexcept { return mIterator->value(); }
34
35 IteratorType& operator++() noexcept {
36 ++mIterator;
37 return *this;
38 }
39
40 [[nodiscard]] bool operator==(IteratorType const&) const noexcept = default;
41 };
42
43 InstancedThreadLocal() : mConstructor([](T* value) { ::std::construct_at(value); }) {}
44
45 explicit InstancedThreadLocal(::std::function<void(T*)> constructor) : mConstructor(::std::move(constructor)) {}
46
47 InstancedThreadLocal(InstancedThreadLocal const&) = delete;
48 InstancedThreadLocal& operator=(InstancedThreadLocal const&) = delete;
49
50 ~InstancedThreadLocal() { destroyItems(); }
51
52 [[nodiscard]] T& operator*() { return *load(); }
53 [[nodiscard]] T* operator->() { return load(); }
54
55 [[nodiscard]] IteratorType begin() const noexcept { return IteratorType{mItems.begin()}; }
56 [[nodiscard]] IteratorType end() const noexcept { return IteratorType{mItems.end()}; }
57
58private:
59 T* load() {
60 if (auto item = static_cast<Item*>(mKey.getValue())) {
61 return item->value();
62 }
63 ItemAllocator allocator;
64 Item* item = ItemTraits::allocate(allocator, 1);
65 ::std::construct_at(item);
66 mConstructor(item->value());
67 mKey.setValue(item);
68 ::std::lock_guard lock{mMutex};
69 mItems.push_back(*item);
70 return item->value();
71 }
72
73 void destroyItems() {
74 ItemAllocator allocator;
75 ::std::lock_guard lock{mMutex};
76 while (!mItems.empty()) {
77 Item& item = mItems.front();
78 ::std::destroy_at(item.value());
79 ::std::destroy_at(&item);
80 ItemTraits::deallocate(allocator, &item, 1);
81 }
82 }
83
84 ::std::function<void(T*)> mConstructor;
85 mutable ItemList mItems;
86 ::std::mutex mMutex;
87 ::Bedrock::Threading::TlsSlot mKey;
88};
89
90} // namespace Bedrock::Threading
Definition list_base_hook.h:10
Definition list.h:14
Definition InstancedThreadLocalBase.h:7
Definition InstancedThreadLocal.h:24
STL namespace.