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  
#include <boost/url/detail/config.hpp>
10  
#include <boost/url/detail/config.hpp>
11  
#include <boost/url/grammar/detail/recycled.hpp>
11  
#include <boost/url/grammar/detail/recycled.hpp>
12  
#include <cstdlib>
12  
#include <cstdlib>
13  
#include <utility>
13  
#include <utility>
14  
#include <atomic>
14  
#include <atomic>
15  

15  

16  
#ifdef BOOST_URL_REPORT
16  
#ifdef BOOST_URL_REPORT
17  
# ifdef _MSC_VER
17  
# ifdef _MSC_VER
18  
#  include <intrin.h>
18  
#  include <intrin.h>
19  
# endif
19  
# endif
20  
#endif
20  
#endif
21  

21  

22  
namespace boost {
22  
namespace boost {
23  
namespace urls {
23  
namespace urls {
24  
namespace grammar {
24  
namespace grammar {
25  
namespace detail {
25  
namespace detail {
26  

26  

27  
struct all_reports
27  
struct all_reports
28  
{
28  
{
29  
    // current count
29  
    // current count
30  
    std::atomic<std::size_t> count = {0};
30  
    std::atomic<std::size_t> count = {0};
31  

31  

32  
    // current bytes
32  
    // current bytes
33  
    std::atomic<std::size_t> bytes = {0};
33  
    std::atomic<std::size_t> bytes = {0};
34  

34  

35  
    // highest total ptr count
35  
    // highest total ptr count
36  
    std::atomic<std::size_t> count_max = {0};
36  
    std::atomic<std::size_t> count_max = {0};
37  

37  

38  
    // highest total bytes
38  
    // highest total bytes
39  
    std::atomic<std::size_t> bytes_max = {0};
39  
    std::atomic<std::size_t> bytes_max = {0};
40  

40  

41  
    // largest single allocation
41  
    // largest single allocation
42  
    std::atomic<std::size_t> alloc_max = {0};
42  
    std::atomic<std::size_t> alloc_max = {0};
43  

43  

44  
    ~all_reports()
44  
    ~all_reports()
45  
    {
45  
    {
46  
        // breakpoint here to view report
46  
        // breakpoint here to view report
47  
#ifdef BOOST_URL_REPORT
47  
#ifdef BOOST_URL_REPORT
48  
# ifdef _MSC_VER
48  
# ifdef _MSC_VER
49  
        if(count_max > 0)
49  
        if(count_max > 0)
50  
            ::__debugbreak();
50  
            ::__debugbreak();
51  
# endif
51  
# endif
52  
#endif
52  
#endif
53  
    }
53  
    }
54  
};
54  
};
55  

55  

56  
static all_reports all_reports_;
56  
static all_reports all_reports_;
57  
} // detail
57  
} // detail
58  

58  

59  
namespace implementation_defined {
59  
namespace implementation_defined {
60  
void
60  
void
61  
recycled_add_impl(
61  
recycled_add_impl(
62  
    std::size_t n) noexcept
62  
    std::size_t n) noexcept
63  
{
63  
{
64  
    auto& a = detail::all_reports_;
64  
    auto& a = detail::all_reports_;
65  

65  

66  
    // LCOV_EXCL_START
66  
    // LCOV_EXCL_START
67  
    /*
67  
    /*
68  
     * We can't guarantee coverage
68  
     * We can't guarantee coverage
69  
     * exercise of this path.
69  
     * exercise of this path.
70  
     */
70  
     */
71  
    std::size_t new_count = ++a.count;
71  
    std::size_t new_count = ++a.count;
72  
    std::size_t old_count_max = a.count_max;
72  
    std::size_t old_count_max = a.count_max;
73  
    while (
73  
    while (
74  
        old_count_max < new_count &&
74  
        old_count_max < new_count &&
75  
        !a.count_max.compare_exchange_weak(
75  
        !a.count_max.compare_exchange_weak(
76  
            old_count_max, new_count))
76  
            old_count_max, new_count))
77  
    {}
77  
    {}
78  

78  

79  
    std::size_t new_bytes = a.bytes.fetch_add(n) + n;
79  
    std::size_t new_bytes = a.bytes.fetch_add(n) + n;
80  
    std::size_t old_bytes_max = a.bytes_max;
80  
    std::size_t old_bytes_max = a.bytes_max;
81  
    while (
81  
    while (
82  
        old_bytes_max < new_bytes &&
82  
        old_bytes_max < new_bytes &&
83  
        !a.bytes_max.compare_exchange_weak(
83  
        !a.bytes_max.compare_exchange_weak(
84  
            old_bytes_max, new_bytes))
84  
            old_bytes_max, new_bytes))
85  
    {}
85  
    {}
86  

86  

87  
    std::size_t old_alloc_max = a.alloc_max;
87  
    std::size_t old_alloc_max = a.alloc_max;
88  
    while (
88  
    while (
89  
        old_alloc_max < n &&
89  
        old_alloc_max < n &&
90  
        !a.alloc_max.compare_exchange_weak(
90  
        !a.alloc_max.compare_exchange_weak(
91  
            old_alloc_max, n))
91  
            old_alloc_max, n))
92  
    {}
92  
    {}
93  
    // LCOV_EXCL_STOP
93  
    // LCOV_EXCL_STOP
94  
}
94  
}
95  

95  

96  
void
96  
void
97  
recycled_remove_impl(
97  
recycled_remove_impl(
98  
    std::size_t n) noexcept
98  
    std::size_t n) noexcept
99  
{
99  
{
100  
    detail::all_reports_.count--;
100  
    detail::all_reports_.count--;
101  
    detail::all_reports_.bytes-=n;
101  
    detail::all_reports_.bytes-=n;
102  
}
102  
}
103  
} // implementation_defined
103  
} // implementation_defined
104  
} // grammar
104  
} // grammar
105  
} // urls
105  
} // urls
106  
} // boost
106  
} // boost