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