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