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  
    */
95  
    T* get() const noexcept
95  
    T* get() const noexcept
96  
    {
96  
    {
97  
        return ptr_;
97  
        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  
    */
104  
    void set(T* p) noexcept
104  
    void set(T* p) noexcept
105  
    {
105  
    {
106  
        ptr_ = p;
106  
        ptr_ = p;
107  
    }
107  
    }
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