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*
90  
    get() const noexcept
90  
    get() const noexcept
91  
    {
91  
    {
92  
        return ptr_;
92  
        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
100  
    set(T* p) noexcept
100  
    set(T* p) noexcept
101  
    {
101  
    {
102  
        ptr_ = p;
102  
        ptr_ = p;
103  
    }
103  
    }
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&
110  
    operator*() const noexcept
110  
    operator*() const noexcept
111  
    {
111  
    {
112  
        return *ptr_;
112  
        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*
120  
    operator->() const noexcept
120  
    operator->() const noexcept
121  
        requires std::is_class_v<T>
121  
        requires std::is_class_v<T>
122  
    {
122  
    {
123  
        return ptr_;
123  
        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*
132  
    operator=(T* p) noexcept
132  
    operator=(T* p) noexcept
133  
    {
133  
    {
134  
        ptr_ = p;
134  
        ptr_ = p;
135  
        return p;
135  
        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