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