include/boost/corosio/detail/thread_local_ptr.hpp

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