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/corosio
7  
// Official repository: https://github.com/cppalliance/corosio
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_COROSIO_DETAIL_THREAD_LOCAL_PTR_HPP
10  
#ifndef BOOST_COROSIO_DETAIL_THREAD_LOCAL_PTR_HPP
11  
#define BOOST_COROSIO_DETAIL_THREAD_LOCAL_PTR_HPP
11  
#define BOOST_COROSIO_DETAIL_THREAD_LOCAL_PTR_HPP
12  

12  

13  
#include <boost/corosio/detail/config.hpp>
13  
#include <boost/corosio/detail/config.hpp>
14  

14  

15  
#include <type_traits>
15  
#include <type_traits>
16  

16  

17  
// Detect thread-local storage mechanism
17  
// Detect thread-local storage mechanism
18  
#if !defined(BOOST_COROSIO_TLS_KEYWORD)
18  
#if !defined(BOOST_COROSIO_TLS_KEYWORD)
19  
# if defined(_MSC_VER)
19  
# if defined(_MSC_VER)
20  
#  define BOOST_COROSIO_TLS_KEYWORD __declspec(thread)
20  
#  define BOOST_COROSIO_TLS_KEYWORD __declspec(thread)
21  
# elif defined(__GNUC__) || defined(__clang__)
21  
# elif defined(__GNUC__) || defined(__clang__)
22  
#  define BOOST_COROSIO_TLS_KEYWORD __thread
22  
#  define BOOST_COROSIO_TLS_KEYWORD __thread
23  
# endif
23  
# endif
24  
#endif
24  
#endif
25  

25  

26  
namespace boost::corosio::detail {
26  
namespace boost::corosio::detail {
27  

27  

28  
/** A thread-local pointer.
28  
/** A thread-local pointer.
29  

29  

30  
    This class provides thread-local storage for a pointer to T.
30  
    This class provides thread-local storage for a pointer to T.
31  
    Each thread has its own independent pointer value, initially
31  
    Each thread has its own independent pointer value, initially
32  
    nullptr. The user is responsible for managing the lifetime
32  
    nullptr. The user is responsible for managing the lifetime
33  
    of the pointed-to objects.
33  
    of the pointed-to objects.
34  

34  

35  
    The storage is static per type T. All instances of
35  
    The storage is static per type T. All instances of
36  
    `thread_local_ptr<T>` share the same underlying slot.
36  
    `thread_local_ptr<T>` share the same underlying slot.
37  

37  

38  
    The implementation uses the most efficient available mechanism:
38  
    The implementation uses the most efficient available mechanism:
39  
    1. Compiler keyword (__declspec(thread) or __thread) - enforces POD
39  
    1. Compiler keyword (__declspec(thread) or __thread) - enforces POD
40  
    2. C++11 thread_local (fallback)
40  
    2. C++11 thread_local (fallback)
41  

41  

42  
    @tparam T The pointed-to type.
42  
    @tparam T The pointed-to type.
43  

43  

44  
    @par Declaration
44  
    @par Declaration
45  

45  

46  
    Typically declared at namespace or class scope. The object
46  
    Typically declared at namespace or class scope. The object
47  
    is stateless, so local variables work but are redundant.
47  
    is stateless, so local variables work but are redundant.
48  

48  

49  
    @code
49  
    @code
50  
    // Recommended: namespace scope
50  
    // Recommended: namespace scope
51  
    namespace {
51  
    namespace {
52  
    thread_local_ptr<session> current_session;
52  
    thread_local_ptr<session> current_session;
53  
    }
53  
    }
54  

54  

55  
    // Also works: static class member
55  
    // Also works: static class member
56  
    class server {
56  
    class server {
57  
        static thread_local_ptr<request> current_request_;
57  
        static thread_local_ptr<request> current_request_;
58  
    };
58  
    };
59  

59  

60  
    // Works but unusual: local variable (still accesses static storage)
60  
    // Works but unusual: local variable (still accesses static storage)
61  
    void foo() {
61  
    void foo() {
62  
        thread_local_ptr<context> ctx;  // same slot on every call
62  
        thread_local_ptr<context> ctx;  // same slot on every call
63  
        ctx = new context();
63  
        ctx = new context();
64  
    }
64  
    }
65  
    @endcode
65  
    @endcode
66  

66  

67  
    @note The user is responsible for deleting pointed-to objects
67  
    @note The user is responsible for deleting pointed-to objects
68  
    before threads exit to avoid memory leaks.
68  
    before threads exit to avoid memory leaks.
69  
*/
69  
*/
70  
template<class T>
70  
template<class T>
71  
class thread_local_ptr;
71  
class thread_local_ptr;
72  

72  

73  
//------------------------------------------------------------------------------
73  
//------------------------------------------------------------------------------
74  

74  

75  
#if defined(BOOST_COROSIO_TLS_KEYWORD)
75  
#if defined(BOOST_COROSIO_TLS_KEYWORD)
76  

76  

77  
// Use compiler-specific keyword (__declspec(thread) or __thread)
77  
// Use compiler-specific keyword (__declspec(thread) or __thread)
78  
// Most efficient: static linkage, no dynamic init, enforces POD
78  
// Most efficient: static linkage, no dynamic init, enforces POD
79  

79  

80  
template<class T>
80  
template<class T>
81  
class thread_local_ptr
81  
class thread_local_ptr
82  
{
82  
{
83  
    static BOOST_COROSIO_TLS_KEYWORD T* ptr_;
83  
    static BOOST_COROSIO_TLS_KEYWORD T* ptr_;
84  

84  

85  
public:
85  
public:
86  
    thread_local_ptr() = default;
86  
    thread_local_ptr() = default;
87  
    ~thread_local_ptr() = default;
87  
    ~thread_local_ptr() = default;
88  

88  

89  
    thread_local_ptr(thread_local_ptr const&) = delete;
89  
    thread_local_ptr(thread_local_ptr const&) = delete;
90  
    thread_local_ptr& operator=(thread_local_ptr const&) = delete;
90  
    thread_local_ptr& operator=(thread_local_ptr const&) = delete;
91  

91  

92  
    /** Return the pointer for this thread.
92  
    /** Return the pointer for this thread.
93  

93  

94  
        @return The stored pointer, or nullptr if not set.
94  
        @return The stored pointer, or nullptr if not set.
95  
    */
95  
    */
96  
    T*
96  
    T*
97  
    get() const noexcept
97  
    get() const noexcept
98  
    {
98  
    {
99  
        return ptr_;
99  
        return ptr_;
100  
    }
100  
    }
101  

101  

102  
    /** Set the pointer for this thread.
102  
    /** Set the pointer for this thread.
103  

103  

104  
        @param p The pointer to store. The user manages its lifetime.
104  
        @param p The pointer to store. The user manages its lifetime.
105  
    */
105  
    */
106  
    void
106  
    void
107  
    set(T* p) noexcept
107  
    set(T* p) noexcept
108  
    {
108  
    {
109  
        ptr_ = p;
109  
        ptr_ = p;
110  
    }
110  
    }
111  

111  

112  
    /** Dereference the stored pointer.
112  
    /** Dereference the stored pointer.
113  

113  

114  
        @pre get() != nullptr
114  
        @pre get() != nullptr
115  
    */
115  
    */
116  
    T&
116  
    T&
117  
    operator*() const noexcept
117  
    operator*() const noexcept
118  
    {
118  
    {
119  
        return *ptr_;
119  
        return *ptr_;
120  
    }
120  
    }
121  

121  

122  
    /** Member access through the stored pointer.
122  
    /** Member access through the stored pointer.
123  

123  

124  
        @pre get() != nullptr
124  
        @pre get() != nullptr
125  
    */
125  
    */
126  
    T*
126  
    T*
127  
    operator->() const noexcept
127  
    operator->() const noexcept
128  
        requires std::is_class_v<T>
128  
        requires std::is_class_v<T>
129  
    {
129  
    {
130  
        return ptr_;
130  
        return ptr_;
131  
    }
131  
    }
132  

132  

133  
    /** Assign a pointer value.
133  
    /** Assign a pointer value.
134  

134  

135  
        @param p The pointer to store.
135  
        @param p The pointer to store.
136  
        @return The stored pointer.
136  
        @return The stored pointer.
137  
    */
137  
    */
138  
    T*
138  
    T*
139  
    operator=(T* p) noexcept
139  
    operator=(T* p) noexcept
140  
    {
140  
    {
141  
        ptr_ = p;
141  
        ptr_ = p;
142  
        return p;
142  
        return p;
143  
    }
143  
    }
144  
};
144  
};
145  

145  

146  
template<class T>
146  
template<class T>
147  
BOOST_COROSIO_TLS_KEYWORD T* thread_local_ptr<T>::ptr_ = nullptr;
147  
BOOST_COROSIO_TLS_KEYWORD T* thread_local_ptr<T>::ptr_ = nullptr;
148  

148  

149  
//------------------------------------------------------------------------------
149  
//------------------------------------------------------------------------------
150  

150  

151  
#else
151  
#else
152  

152  

153  
// Use C++11 thread_local keyword (fallback)
153  
// Use C++11 thread_local keyword (fallback)
154  

154  

155  
template<class T>
155  
template<class T>
156  
class thread_local_ptr
156  
class thread_local_ptr
157  
{
157  
{
158  
    static thread_local T* ptr_;
158  
    static thread_local T* ptr_;
159  

159  

160  
public:
160  
public:
161  
    thread_local_ptr() = default;
161  
    thread_local_ptr() = default;
162  
    ~thread_local_ptr() = default;
162  
    ~thread_local_ptr() = default;
163  

163  

164  
    thread_local_ptr(thread_local_ptr const&) = delete;
164  
    thread_local_ptr(thread_local_ptr const&) = delete;
165  
    thread_local_ptr& operator=(thread_local_ptr const&) = delete;
165  
    thread_local_ptr& operator=(thread_local_ptr const&) = delete;
166  

166  

167  
    T*
167  
    T*
168  
    get() const noexcept
168  
    get() const noexcept
169  
    {
169  
    {
170  
        return ptr_;
170  
        return ptr_;
171  
    }
171  
    }
172  

172  

173  
    void
173  
    void
174  
    set(T* p) noexcept
174  
    set(T* p) noexcept
175  
    {
175  
    {
176  
        ptr_ = p;
176  
        ptr_ = p;
177  
    }
177  
    }
178  

178  

179  
    T&
179  
    T&
180  
    operator*() const noexcept
180  
    operator*() const noexcept
181  
    {
181  
    {
182  
        return *ptr_;
182  
        return *ptr_;
183  
    }
183  
    }
184  

184  

185  
    T*
185  
    T*
186  
    operator->() const noexcept
186  
    operator->() const noexcept
187  
        requires std::is_class_v<T>
187  
        requires std::is_class_v<T>
188  
    {
188  
    {
189  
        return ptr_;
189  
        return ptr_;
190  
    }
190  
    }
191  

191  

192  
    T*
192  
    T*
193  
    operator=(T* p) noexcept
193  
    operator=(T* p) noexcept
194  
    {
194  
    {
195  
        ptr_ = p;
195  
        ptr_ = p;
196  
        return p;
196  
        return p;
197  
    }
197  
    }
198  
};
198  
};
199  

199  

200  
template<class T>
200  
template<class T>
201  
thread_local T* thread_local_ptr<T>::ptr_ = nullptr;
201  
thread_local T* thread_local_ptr<T>::ptr_ = nullptr;
202  

202  

203  
#endif
203  
#endif
204  

204  

205  
} // namespace boost::corosio::detail
205  
} // namespace boost::corosio::detail
206  

206  

207  
#endif
207  
#endif