TLA 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 : #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 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
|