TLA Line data 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 HIT 440762 : T* get() const noexcept
96 : {
97 440762 : 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 32259 : void set(T* p) noexcept
105 : {
106 32259 : ptr_ = p;
107 32259 : }
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
|