100.00% Lines (73/73)
100.00% Functions (10/10)
| TLA | Baseline | Branch | ||||||
|---|---|---|---|---|---|---|---|---|
| Line | Hits | Code | Line | Hits | Code | |||
| 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 | #include <boost/throw_exception.hpp> | 17 | #include <boost/throw_exception.hpp> | |||||
| 18 | 18 | |||||||
| 19 | #include <memory> | 19 | #include <memory> | |||||
| 20 | #include <new> | 20 | #include <new> | |||||
| 21 | 21 | |||||||
| 22 | namespace boost { | 22 | namespace boost { | |||||
| 23 | namespace json { | 23 | namespace json { | |||||
| 24 | 24 | |||||||
| 25 | struct alignas(core::max_align_t) | 25 | struct alignas(core::max_align_t) | |||||
| 26 | monotonic_resource::block : block_base | 26 | monotonic_resource::block : block_base | |||||
| 27 | { | 27 | { | |||||
| 28 | }; | 28 | }; | |||||
| 29 | 29 | |||||||
| 30 | constexpr | 30 | constexpr | |||||
| 31 | std::size_t | 31 | std::size_t | |||||
| HITCBC | 32 | 210 | monotonic_resource:: | 32 | 210 | monotonic_resource:: | ||
| 33 | max_size() | 33 | max_size() | |||||
| 34 | { | 34 | { | |||||
| HITCBC | 35 | 210 | return std::size_t(-1) - sizeof(block); | 35 | 210 | return std::size_t(-1) - sizeof(block); | ||
| 36 | } | 36 | } | |||||
| 37 | 37 | |||||||
| 38 | // lowest power of 2 greater than or equal to n | 38 | // lowest power of 2 greater than or equal to n | |||||
| 39 | std::size_t | 39 | std::size_t | |||||
| HITCBC | 40 | 46 | monotonic_resource:: | 40 | 46 | monotonic_resource:: | ||
| 41 | round_pow2( | 41 | round_pow2( | |||||
| 42 | std::size_t n) noexcept | 42 | std::size_t n) noexcept | |||||
| 43 | { | 43 | { | |||||
| HITCBC | 44 | 46 | if(n & (n - 1)) | 44 | 46 | if(n & (n - 1)) | ||
| HITCBC | 45 | 8 | return next_pow2(n); | 45 | 8 | return next_pow2(n); | ||
| HITCBC | 46 | 38 | return n; | 46 | 38 | return n; | ||
| 47 | } | 47 | } | |||||
| 48 | 48 | |||||||
| 49 | // lowest power of 2 greater than n | 49 | // lowest power of 2 greater than n | |||||
| 50 | std::size_t | 50 | std::size_t | |||||
| HITCBC | 51 | 55 | monotonic_resource:: | 51 | 55 | monotonic_resource:: | ||
| 52 | next_pow2( | 52 | next_pow2( | |||||
| 53 | std::size_t n) noexcept | 53 | std::size_t n) noexcept | |||||
| 54 | { | 54 | { | |||||
| HITCBC | 55 | 55 | std::size_t result = min_size_; | 55 | 55 | std::size_t result = min_size_; | ||
| HITCBC | 56 | 225 | while(result <= n) | 56 | 225 | while(result <= n) | ||
| 57 | { | 57 | { | |||||
| HITCBC | 58 | 171 | if(result >= max_size() - result) | 58 | 171 | if(result >= max_size() - result) | ||
| 59 | { | 59 | { | |||||
| 60 | // overflow | 60 | // overflow | |||||
| HITCBC | 61 | 1 | result = max_size(); | 61 | 1 | result = max_size(); | ||
| HITCBC | 62 | 1 | break; | 62 | 1 | break; | ||
| 63 | } | 63 | } | |||||
| HITCBC | 64 | 170 | result *= 2; | 64 | 170 | result *= 2; | ||
| 65 | } | 65 | } | |||||
| HITCBC | 66 | 55 | return result; | 66 | 55 | return result; | ||
| 67 | } | 67 | } | |||||
| 68 | 68 | |||||||
| 69 | //---------------------------------------------------------- | 69 | //---------------------------------------------------------- | |||||
| 70 | 70 | |||||||
| HITCBC | 71 | 53 | monotonic_resource:: | 71 | 53 | monotonic_resource:: | ||
| HITCBC | 72 | 53 | ~monotonic_resource() | 72 | 53 | ~monotonic_resource() | ||
| 73 | { | 73 | { | |||||
| HITCBC | 74 | 53 | release(); | 74 | 53 | release(); | ||
| HITCBC | 75 | 53 | } | 75 | 53 | } | ||
| 76 | 76 | |||||||
| HITCBC | 77 | 43 | monotonic_resource:: | 77 | 43 | monotonic_resource:: | ||
| 78 | monotonic_resource( | 78 | monotonic_resource( | |||||
| 79 | std::size_t initial_size, | 79 | std::size_t initial_size, | |||||
| HITCBC | 80 | 43 | storage_ptr upstream) noexcept | 80 | 43 | storage_ptr upstream) noexcept | ||
| HITCBC | 81 | 43 | : buffer_{ | 81 | 43 | : buffer_{ | ||
| 82 | nullptr, 0, 0, nullptr} | 82 | nullptr, 0, 0, nullptr} | |||||
| HITCBC | 83 | 86 | , next_size_(round_pow2(initial_size)) | 83 | 86 | , next_size_(round_pow2(initial_size)) | ||
| HITCBC | 84 | 43 | , upstream_(std::move(upstream)) | 84 | 43 | , upstream_(std::move(upstream)) | ||
| 85 | { | 85 | { | |||||
| HITCBC | 86 | 43 | } | 86 | 43 | } | ||
| 87 | 87 | |||||||
| HITCBC | 88 | 10 | monotonic_resource:: | 88 | 10 | monotonic_resource:: | ||
| 89 | monotonic_resource( | 89 | monotonic_resource( | |||||
| 90 | unsigned char* buffer, | 90 | unsigned char* buffer, | |||||
| 91 | std::size_t size, | 91 | std::size_t size, | |||||
| HITCBC | 92 | 10 | storage_ptr upstream) noexcept | 92 | 10 | storage_ptr upstream) noexcept | ||
| HITCBC | 93 | 10 | : buffer_{ | 93 | 10 | : buffer_{ | ||
| 94 | buffer, size, size, nullptr} | 94 | buffer, size, size, nullptr} | |||||
| HITCBC | 95 | 20 | , next_size_(next_pow2(size)) | 95 | 20 | , next_size_(next_pow2(size)) | ||
| HITCBC | 96 | 10 | , upstream_(std::move(upstream)) | 96 | 10 | , upstream_(std::move(upstream)) | ||
| 97 | { | 97 | { | |||||
| HITCBC | 98 | 10 | } | 98 | 10 | } | ||
| 99 | 99 | |||||||
| 100 | void | 100 | void | |||||
| HITCBC | 101 | 54 | monotonic_resource:: | 101 | 54 | monotonic_resource:: | ||
| 102 | release() noexcept | 102 | release() noexcept | |||||
| 103 | { | 103 | { | |||||
| HITCBC | 104 | 54 | auto p = head_; | 104 | 54 | auto p = head_; | ||
| HITCBC | 105 | 91 | while(p != &buffer_) | 105 | 91 | while(p != &buffer_) | ||
| 106 | { | 106 | { | |||||
| HITCBC | 107 | 37 | auto next = p->next; | 107 | 37 | auto next = p->next; | ||
| HITCBC | 108 | 37 | upstream_->deallocate(p, sizeof(block) + p->size); | 108 | 37 | upstream_->deallocate(p, sizeof(block) + p->size); | ||
| HITCBC | 109 | 37 | p = next; | 109 | 37 | p = next; | ||
| 110 | } | 110 | } | |||||
| HITCBC | 111 | 54 | buffer_.p = reinterpret_cast< | 111 | 54 | buffer_.p = reinterpret_cast< | ||
| HITCBC | 112 | 54 | unsigned char*>(buffer_.p) - ( | 112 | 54 | unsigned char*>(buffer_.p) - ( | ||
| HITCBC | 113 | 54 | buffer_.size - buffer_.avail); | 113 | 54 | buffer_.size - buffer_.avail); | ||
| HITCBC | 114 | 54 | buffer_.avail = buffer_.size; | 114 | 54 | buffer_.avail = buffer_.size; | ||
| HITCBC | 115 | 54 | head_ = &buffer_; | 115 | 54 | head_ = &buffer_; | ||
| HITCBC | 116 | 54 | } | 116 | 54 | } | ||
| 117 | 117 | |||||||
| 118 | void* | 118 | void* | |||||
| HITCBC | 119 | 129502 | monotonic_resource:: | 119 | 129502 | monotonic_resource:: | ||
| 120 | do_allocate( | 120 | do_allocate( | |||||
| 121 | std::size_t n, | 121 | std::size_t n, | |||||
| 122 | std::size_t align) | 122 | std::size_t align) | |||||
| 123 | { | 123 | { | |||||
| HITCBC | 124 | 129502 | auto p = std::align(align, n, head_->p, head_->avail); | 124 | 129502 | auto p = std::align(align, n, head_->p, head_->avail); | ||
| HITCBC | 125 | 129502 | if(p) | 125 | 129502 | if(p) | ||
| 126 | { | 126 | { | |||||
| HITCBC | 127 | 129464 | head_->p = reinterpret_cast< | 127 | 129464 | head_->p = reinterpret_cast< | ||
| HITCBC | 128 | 129464 | unsigned char*>(p) + n; | 128 | 129464 | unsigned char*>(p) + n; | ||
| HITCBC | 129 | 129464 | head_->avail -= n; | 129 | 129464 | head_->avail -= n; | ||
| HITCBC | 130 | 129464 | return p; | 130 | 129464 | return p; | ||
| 131 | } | 131 | } | |||||
| 132 | 132 | |||||||
| 133 | // a new block is only aligned to alignof(block), so an | 133 | // a new block is only aligned to alignof(block), so an | |||||
| 134 | // over-aligned request may need up to align - alignof(block) | 134 | // over-aligned request may need up to align - alignof(block) | |||||
| 135 | // bytes of padding in addition to n | 135 | // bytes of padding in addition to n | |||||
| HITCBC | 136 | 38 | std::size_t const pad = align > alignof(block) | 136 | 38 | std::size_t const pad = align > alignof(block) | ||
| HITCBC | 137 | 38 | ? align - alignof(block) : 0; | 137 | 38 | ? align - alignof(block) : 0; | ||
| HITCBC | 138 | 38 | if(n > max_size() - pad) | 138 | 38 | if(n > max_size() - pad) | ||
| HITCBC | 139 | 2 | throw_exception( std::bad_alloc(), BOOST_CURRENT_LOCATION ); | 139 | 2 | throw_exception( std::bad_alloc(), BOOST_CURRENT_LOCATION ); | ||
| HITCBC | 140 | 37 | if(next_size_ < n + pad) | 140 | 37 | if(next_size_ < n + pad) | ||
| HITCBC | 141 | 3 | next_size_ = round_pow2(n + pad); | 141 | 3 | next_size_ = round_pow2(n + pad); | ||
| HITCBC | 142 | 37 | auto b = ::new(upstream_->allocate( | 142 | 37 | auto b = ::new(upstream_->allocate( | ||
| HITCBC | 143 | 37 | sizeof(block) + next_size_)) block; | 143 | 37 | sizeof(block) + next_size_)) block; | ||
| HITCBC | 144 | 37 | b->p = b + 1; | 144 | 37 | b->p = b + 1; | ||
| HITCBC | 145 | 37 | b->avail = next_size_; | 145 | 37 | b->avail = next_size_; | ||
| HITCBC | 146 | 37 | b->size = next_size_; | 146 | 37 | b->size = next_size_; | ||
| HITCBC | 147 | 37 | b->next = head_; | 147 | 37 | b->next = head_; | ||
| HITCBC | 148 | 37 | head_ = b; | 148 | 37 | head_ = b; | ||
| HITCBC | 149 | 37 | next_size_ = next_pow2(next_size_); | 149 | 37 | next_size_ = next_pow2(next_size_); | ||
| 150 | 150 | |||||||
| HITCBC | 151 | 37 | p = std::align(align, n, head_->p, head_->avail); | 151 | 37 | p = std::align(align, n, head_->p, head_->avail); | ||
| HITCBC | 152 | 37 | BOOST_ASSERT(p); | 152 | 37 | BOOST_ASSERT(p); | ||
| HITCBC | 153 | 37 | head_->p = reinterpret_cast< | 153 | 37 | head_->p = reinterpret_cast< | ||
| HITCBC | 154 | 37 | unsigned char*>(p) + n; | 154 | 37 | unsigned char*>(p) + n; | ||
| HITCBC | 155 | 37 | head_->avail -= n; | 155 | 37 | head_->avail -= n; | ||
| HITCBC | 156 | 37 | return p; | 156 | 37 | return p; | ||
| 157 | } | 157 | } | |||||
| 158 | 158 | |||||||
| 159 | void | 159 | void | |||||
| HITCBC | 160 | 29 | monotonic_resource:: | 160 | 29 | monotonic_resource:: | ||
| 161 | do_deallocate( | 161 | do_deallocate( | |||||
| 162 | void*, | 162 | void*, | |||||
| 163 | std::size_t, | 163 | std::size_t, | |||||
| 164 | std::size_t) | 164 | std::size_t) | |||||
| 165 | { | 165 | { | |||||
| 166 | // do nothing | 166 | // do nothing | |||||
| HITCBC | 167 | 29 | } | 167 | 29 | } | ||
| 168 | 168 | |||||||
| 169 | bool | 169 | bool | |||||
| HITCBC | 170 | 1 | monotonic_resource:: | 170 | 1 | monotonic_resource:: | ||
| 171 | do_is_equal( | 171 | do_is_equal( | |||||
| 172 | memory_resource const& mr) const noexcept | 172 | memory_resource const& mr) const noexcept | |||||
| 173 | { | 173 | { | |||||
| HITCBC | 174 | 1 | return this == &mr; | 174 | 1 | return this == &mr; | ||
| 175 | } | 175 | } | |||||
| 176 | 176 | |||||||
| 177 | } // namespace json | 177 | } // namespace json | |||||
| 178 | } // namespace boost | 178 | } // namespace boost | |||||
| 179 | 179 | |||||||
| 180 | #endif | 180 | #endif | |||||