1  
//
1  
//
2  
// Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2022 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/boostorg/url
7  
// Official repository: https://github.com/boostorg/url
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_URL_GRAMMAR_IMPL_RECYCLED_PTR_HPP
10  
#ifndef BOOST_URL_GRAMMAR_IMPL_RECYCLED_PTR_HPP
11  
#define BOOST_URL_GRAMMAR_IMPL_RECYCLED_PTR_HPP
11  
#define BOOST_URL_GRAMMAR_IMPL_RECYCLED_PTR_HPP
12  

12  

13  
#include <boost/assert.hpp>
13  
#include <boost/assert.hpp>
14  

14  

15  
namespace boost {
15  
namespace boost {
16  
namespace urls {
16  
namespace urls {
17  
namespace grammar {
17  
namespace grammar {
18  

18  

19  
//------------------------------------------------
19  
//------------------------------------------------
20  

20  

21  
template<class T>
21  
template<class T>
22  
recycled<T>::
22  
recycled<T>::
23  
~recycled()
23  
~recycled()
24  
{
24  
{
25  
    std::size_t n = 0;
25  
    std::size_t n = 0;
26  
    // VFALCO we should probably deallocate
26  
    // VFALCO we should probably deallocate
27  
    // in reverse order of allocation but
27  
    // in reverse order of allocation but
28  
    // that requires a doubly-linked list.
28  
    // that requires a doubly-linked list.
29  
    auto it = head_;
29  
    auto it = head_;
30  
    while(it)
30  
    while(it)
31  
    {
31  
    {
32  
        ++n;
32  
        ++n;
33  
        auto next = it->next;
33  
        auto next = it->next;
34  
        BOOST_ASSERT(
34  
        BOOST_ASSERT(
35  
            it->refs == 0);
35  
            it->refs == 0);
36  
        delete it;
36  
        delete it;
37  
        it = next;
37  
        it = next;
38  
    }
38  
    }
39  
    implementation_defined::recycled_remove(
39  
    implementation_defined::recycled_remove(
40  
        sizeof(U) * n);
40  
        sizeof(U) * n);
41  
}
41  
}
42  

42  

43  
template<class T>
43  
template<class T>
44  
auto
44  
auto
45  
recycled<T>::
45  
recycled<T>::
46  
acquire() ->
46  
acquire() ->
47  
    U*
47  
    U*
48  
{
48  
{
49  
    U* p;
49  
    U* p;
50  
    {
50  
    {
51  
#if !defined(BOOST_URL_DISABLE_THREADS)
51  
#if !defined(BOOST_URL_DISABLE_THREADS)
52  
        std::lock_guard<
52  
        std::lock_guard<
53  
            std::mutex> lock(m_);
53  
            std::mutex> lock(m_);
54  
#endif
54  
#endif
55  
        p = head_;
55  
        p = head_;
56  
        if(p)
56  
        if(p)
57  
        {
57  
        {
58  
            // reuse
58  
            // reuse
59  
            head_ = head_->next;
59  
            head_ = head_->next;
60  
            implementation_defined::recycled_remove(
60  
            implementation_defined::recycled_remove(
61  
                sizeof(U));
61  
                sizeof(U));
62  
            ++p->refs;
62  
            ++p->refs;
63  
        }
63  
        }
64  
        else
64  
        else
65  
        {
65  
        {
66  
            p = new U;
66  
            p = new U;
67  
        }
67  
        }
68  
    }
68  
    }
69  
    BOOST_ASSERT(p->refs == 1);
69  
    BOOST_ASSERT(p->refs == 1);
70  
    return p;
70  
    return p;
71  
}
71  
}
72  

72  

73  
template<class T>
73  
template<class T>
74  
void
74  
void
75  
recycled<T>::
75  
recycled<T>::
76  
release(U* u) noexcept
76  
release(U* u) noexcept
77  
{
77  
{
78  
    if(--u->refs != 0)
78  
    if(--u->refs != 0)
79  
        return;
79  
        return;
80  
    {
80  
    {
81  
#if !defined(BOOST_URL_DISABLE_THREADS)
81  
#if !defined(BOOST_URL_DISABLE_THREADS)
82  
        std::lock_guard<
82  
        std::lock_guard<
83  
            std::mutex> lock(m_);
83  
            std::mutex> lock(m_);
84  
#endif
84  
#endif
85  
        u->next = head_;
85  
        u->next = head_;
86  
        head_ = u;
86  
        head_ = u;
87  
    }
87  
    }
88  
    implementation_defined::recycled_add(
88  
    implementation_defined::recycled_add(
89  
        sizeof(U));
89  
        sizeof(U));
90  
}
90  
}
91  

91  

92  
//------------------------------------------------
92  
//------------------------------------------------
93  

93  

94  
template<class T>
94  
template<class T>
95  
recycled_ptr<T>::
95  
recycled_ptr<T>::
96  
~recycled_ptr()
96  
~recycled_ptr()
97  
{
97  
{
98  
    if(p_)
98  
    if(p_)
99  
        bin_->release(p_);
99  
        bin_->release(p_);
100  
}
100  
}
101  

101  

102  
template<class T>
102  
template<class T>
103  
recycled_ptr<T>::
103  
recycled_ptr<T>::
104  
recycled_ptr(
104  
recycled_ptr(
105  
    recycled<T>& bin)
105  
    recycled<T>& bin)
106  
    : bin_(&bin)
106  
    : bin_(&bin)
107  
    , p_(bin.acquire())
107  
    , p_(bin.acquire())
108  
{
108  
{
109  
}
109  
}
110  

110  

111  
template<class T>
111  
template<class T>
112  
recycled_ptr<T>::
112  
recycled_ptr<T>::
113  
recycled_ptr(
113  
recycled_ptr(
114  
    recycled<T>& bin,
114  
    recycled<T>& bin,
115  
    std::nullptr_t) noexcept
115  
    std::nullptr_t) noexcept
116  
    : bin_(&bin)
116  
    : bin_(&bin)
117  
{
117  
{
118  
}
118  
}
119  

119  

120  
template<class T>
120  
template<class T>
121  
recycled_ptr<T>::
121  
recycled_ptr<T>::
122  
recycled_ptr()
122  
recycled_ptr()
123  
    : recycled_ptr(nullptr)
123  
    : recycled_ptr(nullptr)
124  
{
124  
{
125  
    p_ = bin_->acquire();
125  
    p_ = bin_->acquire();
126  
}
126  
}
127  

127  

128  
template<class T>
128  
template<class T>
129  
recycled_ptr<T>::
129  
recycled_ptr<T>::
130  
recycled_ptr(
130  
recycled_ptr(
131  
    std::nullptr_t) noexcept
131  
    std::nullptr_t) noexcept
132  
    : recycled_ptr([]() -> B&
132  
    : recycled_ptr([]() -> B&
133  
        {
133  
        {
134  
            // VFALCO need guaranteed constexpr-init
134  
            // VFALCO need guaranteed constexpr-init
135  
            static B r;
135  
            static B r;
136  
            return r;
136  
            return r;
137  
        }(), nullptr)
137  
        }(), nullptr)
138  
{
138  
{
139  
}
139  
}
140  

140  

141  
template<class T>
141  
template<class T>
142  
recycled_ptr<T>::
142  
recycled_ptr<T>::
143  
recycled_ptr(
143  
recycled_ptr(
144  
    recycled_ptr const& other) noexcept
144  
    recycled_ptr const& other) noexcept
145  
    : bin_(other.bin_)
145  
    : bin_(other.bin_)
146  
    , p_(other.p_)
146  
    , p_(other.p_)
147  
{
147  
{
148  
    if(p_)
148  
    if(p_)
149  
        ++p_->refs;
149  
        ++p_->refs;
150  
}
150  
}
151  

151  

152  
template<class T>
152  
template<class T>
153  
recycled_ptr<T>::
153  
recycled_ptr<T>::
154  
recycled_ptr(
154  
recycled_ptr(
155  
    recycled_ptr&& other) noexcept
155  
    recycled_ptr&& other) noexcept
156  
    : bin_(other.bin_)
156  
    : bin_(other.bin_)
157  
    , p_(other.p_)
157  
    , p_(other.p_)
158  
{
158  
{
159  
    other.p_ = nullptr;
159  
    other.p_ = nullptr;
160  
}
160  
}
161  

161  

162  
template<class T>
162  
template<class T>
163  
auto
163  
auto
164  
recycled_ptr<T>::
164  
recycled_ptr<T>::
165  
operator=(
165  
operator=(
166  
    recycled_ptr&& other) noexcept ->
166  
    recycled_ptr&& other) noexcept ->
167  
        recycled_ptr&
167  
        recycled_ptr&
168  
{
168  
{
169  
    BOOST_ASSERT(
169  
    BOOST_ASSERT(
170  
        bin_ == other.bin_);
170  
        bin_ == other.bin_);
171  
    if(p_)
171  
    if(p_)
172  
        bin_->release(p_);
172  
        bin_->release(p_);
173  
    p_ = other.p_;
173  
    p_ = other.p_;
174  
    other.p_ = nullptr;
174  
    other.p_ = nullptr;
175  
    return *this;
175  
    return *this;
176  
}
176  
}
177  

177  

178  
template<class T>
178  
template<class T>
179  
auto
179  
auto
180  
recycled_ptr<T>::
180  
recycled_ptr<T>::
181  
operator=(
181  
operator=(
182  
    recycled_ptr const& other) noexcept ->
182  
    recycled_ptr const& other) noexcept ->
183  
        recycled_ptr&
183  
        recycled_ptr&
184  
{
184  
{
185  
    BOOST_ASSERT(
185  
    BOOST_ASSERT(
186  
        bin_ == other.bin_);
186  
        bin_ == other.bin_);
187  
    if(p_)
187  
    if(p_)
188  
        bin_->release(p_);
188  
        bin_->release(p_);
189  
    p_ = other.p_;
189  
    p_ = other.p_;
190  
    if(p_)
190  
    if(p_)
191  
        ++p_->refs;
191  
        ++p_->refs;
192  
    return *this;
192  
    return *this;
193  
}
193  
}
194  

194  

195  
template<class T>
195  
template<class T>
196  
T&
196  
T&
197  
recycled_ptr<T>::
197  
recycled_ptr<T>::
198  
acquire()
198  
acquire()
199  
{
199  
{
200  
    if(! p_)
200  
    if(! p_)
201  
        p_ = bin_->acquire();
201  
        p_ = bin_->acquire();
202  
    return p_->t;
202  
    return p_->t;
203  
}
203  
}
204  

204  

205  
template<class T>
205  
template<class T>
206  
void
206  
void
207  
recycled_ptr<T>::
207  
recycled_ptr<T>::
208  
release() noexcept
208  
release() noexcept
209  
{
209  
{
210  
    if(p_)
210  
    if(p_)
211  
    {
211  
    {
212  
        bin_->release(p_);
212  
        bin_->release(p_);
213  
        p_ = nullptr;
213  
        p_ = nullptr;
214  
    }
214  
    }
215  
}
215  
}
216  

216  

217  
} // grammar
217  
} // grammar
218  
} // urls
218  
} // urls
219  
} // boost
219  
} // boost
220  

220  

221  
#endif
221  
#endif