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 //
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 #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 687505 T* get() const noexcept
96 {
97 687505 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 36801 void set(T* p) noexcept
105 {
106 36801 ptr_ = p;
107 36801 }
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_TLS_KEYWORD T* thread_local_ptr<T>::ptr_ = nullptr;
143
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 thread_local T* thread_local_ptr<T>::ptr_ = nullptr;
192
193 #endif
194
195 } // namespace boost::corosio::detail
196
197 #endif
198