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