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