Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/cppalliance/capy
8 : //
9 :
10 : #ifndef BOOST_CAPY_THREAD_LOCAL_PTR_HPP
11 : #define BOOST_CAPY_THREAD_LOCAL_PTR_HPP
12 :
13 : #include <boost/capy/detail/config.hpp>
14 :
15 : #include <type_traits>
16 :
17 : namespace boost {
18 : namespace capy {
19 :
20 : /** A thread-local pointer.
21 :
22 : This class provides thread-local storage for a pointer to T.
23 : Each thread has its own independent pointer value, initially
24 : nullptr. The user is responsible for managing the lifetime
25 : of the pointed-to objects.
26 :
27 : The storage is static per type T. All instances of
28 : `thread_local_ptr<T>` share the same underlying slot.
29 :
30 : The implementation uses the most efficient available mechanism:
31 : 1. Compiler keyword (__declspec(thread) or __thread) - enforces POD
32 : 2. C++11 thread_local (fallback)
33 :
34 : @tparam T The pointed-to type.
35 :
36 : @par Declaration
37 :
38 : Typically declared at namespace or class scope. The object
39 : is stateless, so local variables work but are redundant.
40 :
41 : @code
42 : // Recommended: namespace scope
43 : namespace {
44 : thread_local_ptr<session> current_session;
45 : }
46 :
47 : // Also works: static class member
48 : class server {
49 : static thread_local_ptr<request> current_request_;
50 : };
51 :
52 : // Works but unusual: local variable (still accesses static storage)
53 : void foo() {
54 : thread_local_ptr<context> ctx; // same slot on every call
55 : ctx = new context();
56 : }
57 : @endcode
58 :
59 : @note The user is responsible for deleting pointed-to objects
60 : before threads exit to avoid memory leaks.
61 : */
62 : template<class T>
63 : class thread_local_ptr;
64 :
65 : //------------------------------------------------------------------------------
66 :
67 : #if defined(BOOST_CAPY_TLS_KEYWORD)
68 :
69 : // Use compiler-specific keyword (__declspec(thread) or __thread)
70 : // Most efficient: static linkage, no dynamic init, enforces POD
71 :
72 : template<class T>
73 : class thread_local_ptr
74 : {
75 : static BOOST_CAPY_TLS_KEYWORD T* ptr_;
76 :
77 : public:
78 : thread_local_ptr() = default;
79 : ~thread_local_ptr() = default;
80 :
81 : thread_local_ptr(thread_local_ptr const&) = delete;
82 : thread_local_ptr& operator=(thread_local_ptr const&) = delete;
83 :
84 : /** Return the pointer for this thread.
85 :
86 : @return The stored pointer, or nullptr if not set.
87 : */
88 : T*
89 13 : get() const noexcept
90 : {
91 13 : return ptr_;
92 : }
93 :
94 : /** Set the pointer for this thread.
95 :
96 : @param p The pointer to store. The user manages its lifetime.
97 : */
98 : void
99 2 : set(T* p) noexcept
100 : {
101 2 : ptr_ = p;
102 2 : }
103 :
104 : /** Dereference the stored pointer.
105 :
106 : @pre get() != nullptr
107 : */
108 : T&
109 2 : operator*() const noexcept
110 : {
111 2 : return *ptr_;
112 : }
113 :
114 : /** Member access through the stored pointer.
115 :
116 : @pre get() != nullptr
117 : */
118 : T*
119 5 : operator->() const noexcept
120 : requires std::is_class_v<T>
121 : {
122 5 : return ptr_;
123 : }
124 :
125 : /** Assign a pointer value.
126 :
127 : @param p The pointer to store.
128 : @return The stored pointer.
129 : */
130 : T*
131 9 : operator=(T* p) noexcept
132 : {
133 9 : ptr_ = p;
134 9 : return p;
135 : }
136 : };
137 :
138 : template<class T>
139 : BOOST_CAPY_TLS_KEYWORD T* thread_local_ptr<T>::ptr_ = nullptr;
140 :
141 : //------------------------------------------------------------------------------
142 :
143 : #else
144 :
145 : // Use C++11 thread_local keyword (fallback)
146 :
147 : template<class T>
148 : class thread_local_ptr
149 : {
150 : static thread_local T* ptr_;
151 :
152 : public:
153 : thread_local_ptr() = default;
154 : ~thread_local_ptr() = default;
155 :
156 : thread_local_ptr(thread_local_ptr const&) = delete;
157 : thread_local_ptr& operator=(thread_local_ptr const&) = delete;
158 :
159 : T*
160 : get() const noexcept
161 : {
162 : return ptr_;
163 : }
164 :
165 : void
166 : set(T* p) noexcept
167 : {
168 : ptr_ = p;
169 : }
170 :
171 : T&
172 : operator*() const noexcept
173 : {
174 : return *ptr_;
175 : }
176 :
177 : T*
178 : operator->() const noexcept
179 : requires std::is_class_v<T>
180 : {
181 : return ptr_;
182 : }
183 :
184 : T*
185 : operator=(T* p) noexcept
186 : {
187 : ptr_ = p;
188 : return p;
189 : }
190 : };
191 :
192 : template<class T>
193 : thread_local T* thread_local_ptr<T>::ptr_ = nullptr;
194 :
195 : #endif
196 :
197 : } // namespace capy
198 : } // namespace boost
199 :
200 : #endif
|