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