1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
3  
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
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/boostorg/json
8  
// Official repository: https://github.com/boostorg/json
9  
//
9  
//
10  

10  

11  
#ifndef BOOST_JSON_IMPL_MONOTONIC_RESOURCE_IPP
11  
#ifndef BOOST_JSON_IMPL_MONOTONIC_RESOURCE_IPP
12  
#define BOOST_JSON_IMPL_MONOTONIC_RESOURCE_IPP
12  
#define BOOST_JSON_IMPL_MONOTONIC_RESOURCE_IPP
13  

13  

14  
#include <boost/json/monotonic_resource.hpp>
14  
#include <boost/json/monotonic_resource.hpp>
15  
#include <boost/json/detail/except.hpp>
15  
#include <boost/json/detail/except.hpp>
16  
#include <boost/core/max_align.hpp>
16  
#include <boost/core/max_align.hpp>
17  

17  

18  
#include <memory>
18  
#include <memory>
19  

19  

20  
namespace boost {
20  
namespace boost {
21  
namespace json {
21  
namespace json {
22  

22  

23  
struct alignas(core::max_align_t)
23  
struct alignas(core::max_align_t)
24  
    monotonic_resource::block : block_base
24  
    monotonic_resource::block : block_base
25  
{
25  
{
26  
};
26  
};
27  

27  

28  
constexpr
28  
constexpr
29  
std::size_t
29  
std::size_t
30  
monotonic_resource::
30  
monotonic_resource::
31  
max_size()
31  
max_size()
32  
{
32  
{
33  
    return std::size_t(-1) - sizeof(block);
33  
    return std::size_t(-1) - sizeof(block);
34  
}
34  
}
35  

35  

36  
// lowest power of 2 greater than or equal to n
36  
// lowest power of 2 greater than or equal to n
37  
std::size_t
37  
std::size_t
38  
monotonic_resource::
38  
monotonic_resource::
39  
round_pow2(
39  
round_pow2(
40  
    std::size_t n) noexcept
40  
    std::size_t n) noexcept
41  
{
41  
{
42  
    if(n & (n - 1))
42  
    if(n & (n - 1))
43  
        return next_pow2(n);
43  
        return next_pow2(n);
44  
    return n;
44  
    return n;
45  
}
45  
}
46  

46  

47  
// lowest power of 2 greater than n
47  
// lowest power of 2 greater than n
48  
std::size_t
48  
std::size_t
49  
monotonic_resource::
49  
monotonic_resource::
50  
next_pow2(
50  
next_pow2(
51  
    std::size_t n) noexcept
51  
    std::size_t n) noexcept
52  
{
52  
{
53  
    std::size_t result = min_size_;
53  
    std::size_t result = min_size_;
54  
    while(result <= n)
54  
    while(result <= n)
55  
    {
55  
    {
56  
        if(result >= max_size() - result)
56  
        if(result >= max_size() - result)
57  
        {
57  
        {
58  
            // overflow
58  
            // overflow
59  
            result = max_size();
59  
            result = max_size();
60  
            break;
60  
            break;
61  
        }
61  
        }
62  
        result *= 2;
62  
        result *= 2;
63  
    }
63  
    }
64  
    return result;
64  
    return result;
65  
}
65  
}
66  

66  

67  
//----------------------------------------------------------
67  
//----------------------------------------------------------
68  

68  

69  
monotonic_resource::
69  
monotonic_resource::
70  
~monotonic_resource()
70  
~monotonic_resource()
71  
{
71  
{
72  
    release();
72  
    release();
73  
}
73  
}
74  

74  

75  
monotonic_resource::
75  
monotonic_resource::
76  
monotonic_resource(
76  
monotonic_resource(
77  
    std::size_t initial_size,
77  
    std::size_t initial_size,
78  
    storage_ptr upstream) noexcept
78  
    storage_ptr upstream) noexcept
79  
    : buffer_{
79  
    : buffer_{
80  
        nullptr, 0, 0, nullptr}
80  
        nullptr, 0, 0, nullptr}
81  
    , next_size_(round_pow2(initial_size))
81  
    , next_size_(round_pow2(initial_size))
82  
    , upstream_(std::move(upstream))
82  
    , upstream_(std::move(upstream))
83  
{
83  
{
84  
}
84  
}
85  

85  

86  
monotonic_resource::
86  
monotonic_resource::
87  
monotonic_resource(
87  
monotonic_resource(
88  
    unsigned char* buffer,
88  
    unsigned char* buffer,
89  
    std::size_t size,
89  
    std::size_t size,
90  
    storage_ptr upstream) noexcept
90  
    storage_ptr upstream) noexcept
91  
    : buffer_{
91  
    : buffer_{
92  
        buffer, size, size, nullptr}
92  
        buffer, size, size, nullptr}
93  
    , next_size_(next_pow2(size))
93  
    , next_size_(next_pow2(size))
94  
    , upstream_(std::move(upstream))
94  
    , upstream_(std::move(upstream))
95  
{
95  
{
96  
}
96  
}
97  

97  

98  
void
98  
void
99  
monotonic_resource::
99  
monotonic_resource::
100  
release() noexcept
100  
release() noexcept
101  
{
101  
{
102  
    auto p = head_;
102  
    auto p = head_;
103  
    while(p != &buffer_)
103  
    while(p != &buffer_)
104  
    {
104  
    {
105  
        auto next = p->next;
105  
        auto next = p->next;
106  
        upstream_->deallocate(p, p->size);
106  
        upstream_->deallocate(p, p->size);
107  
        p = next;
107  
        p = next;
108  
    }
108  
    }
109  
    buffer_.p = reinterpret_cast<
109  
    buffer_.p = reinterpret_cast<
110  
        unsigned char*>(buffer_.p) - (
110  
        unsigned char*>(buffer_.p) - (
111  
            buffer_.size - buffer_.avail);
111  
            buffer_.size - buffer_.avail);
112  
    buffer_.avail = buffer_.size;
112  
    buffer_.avail = buffer_.size;
113  
    head_ = &buffer_;
113  
    head_ = &buffer_;
114  
}
114  
}
115  

115  

116  
void*
116  
void*
117  
monotonic_resource::
117  
monotonic_resource::
118  
do_allocate(
118  
do_allocate(
119  
    std::size_t n,
119  
    std::size_t n,
120  
    std::size_t align)
120  
    std::size_t align)
121  
{
121  
{
122  
    auto p = std::align(align, n, head_->p, head_->avail);
122  
    auto p = std::align(align, n, head_->p, head_->avail);
123  
    if(p)
123  
    if(p)
124  
    {
124  
    {
125  
        head_->p = reinterpret_cast<
125  
        head_->p = reinterpret_cast<
126  
            unsigned char*>(p) + n;
126  
            unsigned char*>(p) + n;
127  
        head_->avail -= n;
127  
        head_->avail -= n;
128  
        return p;
128  
        return p;
129  
    }
129  
    }
130  

130  

131  
    if(next_size_ < n)
131  
    if(next_size_ < n)
132  
        next_size_ = round_pow2(n);
132  
        next_size_ = round_pow2(n);
133  
    auto b = ::new(upstream_->allocate(
133  
    auto b = ::new(upstream_->allocate(
134  
        sizeof(block) + next_size_)) block;
134  
        sizeof(block) + next_size_)) block;
135  
    b->p = b + 1;
135  
    b->p = b + 1;
136  
    b->avail = next_size_;
136  
    b->avail = next_size_;
137  
    b->size = next_size_;
137  
    b->size = next_size_;
138  
    b->next = head_;
138  
    b->next = head_;
139  
    head_ = b;
139  
    head_ = b;
140  
    next_size_ = next_pow2(next_size_);
140  
    next_size_ = next_pow2(next_size_);
141  

141  

142  
    p = std::align(align, n, head_->p, head_->avail);
142  
    p = std::align(align, n, head_->p, head_->avail);
143  
    BOOST_ASSERT(p);
143  
    BOOST_ASSERT(p);
144  
    head_->p = reinterpret_cast<
144  
    head_->p = reinterpret_cast<
145  
        unsigned char*>(p) + n;
145  
        unsigned char*>(p) + n;
146  
    head_->avail -= n;
146  
    head_->avail -= n;
147  
    return p;
147  
    return p;
148  
}
148  
}
149  

149  

150  
void
150  
void
151  
monotonic_resource::
151  
monotonic_resource::
152  
do_deallocate(
152  
do_deallocate(
153  
    void*,
153  
    void*,
154  
    std::size_t,
154  
    std::size_t,
155  
    std::size_t)
155  
    std::size_t)
156  
{
156  
{
157  
    // do nothing
157  
    // do nothing
158  
}
158  
}
159  

159  

160  
bool
160  
bool
161  
monotonic_resource::
161  
monotonic_resource::
162  
do_is_equal(
162  
do_is_equal(
163  
    memory_resource const& mr) const noexcept
163  
    memory_resource const& mr) const noexcept
164  
{
164  
{
165  
    return this == &mr;
165  
    return this == &mr;
166  
}
166  
}
167  

167  

168  
} // namespace json
168  
} // namespace json
169  
} // namespace boost
169  
} // namespace boost
170  

170  

171  
#endif
171  
#endif