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/align/align.hpp>
16  
#include <boost/core/max_align.hpp>
17  
#include <boost/core/max_align.hpp>
17  

18  

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

20  

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

23  

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

28  

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

36  

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

47  

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

67  

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

69  

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

75  

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

86  

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

98  

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

116  

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

132  

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

143  

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

152  

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

162  

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

170  

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

173  

171  
#endif
174  
#endif