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