Line data Source code
1 : // 2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) 3 : // 4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 : // 7 : // Official repository: https://github.com/cppalliance/http_proto 8 : // 9 : 10 : #include <boost/http_proto/detail/workspace.hpp> 11 : #include <boost/http_proto/detail/except.hpp> 12 : #include <boost/assert.hpp> 13 : 14 : namespace boost { 15 : namespace http_proto { 16 : namespace detail { 17 : 18 : workspace:: 19 : any:: 20 : ~any() = default; 21 : 22 1058 : workspace:: 23 1058 : ~workspace() 24 : { 25 1058 : if(begin_) 26 : { 27 1058 : clear(); 28 1058 : delete[] begin_; 29 : } 30 1058 : } 31 : 32 14 : workspace:: 33 : workspace( 34 14 : std::size_t n) 35 14 : : begin_(new unsigned char[n]) 36 14 : , front_(begin_) 37 14 : , head_(begin_ + n) 38 14 : , back_(head_) 39 14 : , end_(head_) 40 : { 41 14 : } 42 : 43 0 : workspace:: 44 : workspace( 45 0 : workspace&& other) noexcept 46 0 : : begin_(other.begin_) 47 0 : , front_(other.front_) 48 0 : , head_(other.end_) 49 0 : , back_(other.back_) 50 0 : , end_(other.end_) 51 : { 52 0 : other.begin_ = nullptr; 53 0 : other.front_ = nullptr; 54 0 : other.head_ = nullptr; 55 0 : other.back_ = nullptr; 56 0 : other.end_ = nullptr; 57 0 : } 58 : 59 : void 60 1044 : workspace:: 61 : allocate( 62 : std::size_t n) 63 : { 64 : // Cannot be empty 65 1044 : if(n == 0) 66 0 : detail::throw_invalid_argument(); 67 : 68 : // Already allocated 69 1044 : if(begin_ != nullptr) 70 0 : detail::throw_logic_error(); 71 : 72 1044 : begin_ = new unsigned char[n]; 73 1044 : front_ = begin_; 74 1044 : head_ = begin_ + n; 75 1044 : back_ = head_; 76 1044 : end_ = head_; 77 1044 : } 78 : 79 : void 80 4324 : workspace:: 81 : clear() noexcept 82 : { 83 4324 : if(! begin_) 84 0 : return; 85 : 86 4324 : auto const end = 87 : reinterpret_cast< 88 : any const*>(back_); 89 4324 : auto p = 90 : reinterpret_cast< 91 : any const*>(head_); 92 4664 : while(p != end) 93 : { 94 340 : auto next = p->next; 95 340 : p->~any(); 96 340 : p = next; 97 : } 98 4324 : front_ = begin_; 99 4324 : head_ = end_; 100 4324 : back_ = end_; 101 : } 102 : 103 : unsigned char* 104 1329 : workspace:: 105 : reserve_front( 106 : std::size_t n) 107 : { 108 : // 109 : // Requested size exceeds available space. 110 : // Note you can never reserve the last byte. 111 1329 : if(n >= size()) 112 0 : detail::throw_length_error(); 113 : 114 1329 : auto const p = front_; 115 1329 : front_ += n ; 116 1329 : return p; 117 : } 118 : 119 : unsigned char* 120 1329 : workspace:: 121 : reserve_back( 122 : std::size_t n) 123 : { 124 : // can't reserve after acquire 125 1329 : if(head_ != end_) 126 0 : detail::throw_logic_error(); 127 : 128 : // can't reserve twice 129 1329 : if(back_ != end_) 130 0 : detail::throw_logic_error(); 131 : 132 : // over capacity 133 1329 : std::size_t const lim = 134 1329 : head_ - front_; 135 1329 : if(n >= lim) 136 0 : detail::throw_length_error(); 137 : 138 1329 : head_ -= n; 139 1329 : back_ = head_; 140 1329 : return back_; 141 : } 142 : 143 : // https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html 144 : unsigned char* 145 340 : workspace:: 146 : bump_down( 147 : std::size_t size, 148 : std::size_t align) 149 : { 150 340 : BOOST_ASSERT(align > 0); 151 340 : BOOST_ASSERT( 152 : (align & (align - 1)) == 0); 153 340 : BOOST_ASSERT(front_); 154 : 155 340 : auto ip0 = reinterpret_cast< 156 340 : std::uintptr_t>(front_); 157 340 : auto ip = reinterpret_cast< 158 340 : std::uintptr_t>(head_); 159 : 160 : // If you get an exception here, it 161 : // means that a buffer was too small 162 : // for your workload. Increase the 163 : // buffer size. 164 340 : if(size > ip - ip0) 165 0 : detail::throw_bad_alloc(); 166 : 167 340 : ip -= size; 168 340 : ip &= ~(align - 1); 169 : 170 : // If you get an exception here, it 171 : // means that a buffer was too small 172 : // for your workload. Increase the 173 : // buffer size. 174 340 : if(ip < ip0) 175 0 : detail::throw_bad_alloc(); 176 : 177 : return reinterpret_cast< 178 340 : unsigned char*>(ip); 179 : } 180 : 181 : } // detail 182 : } // http_proto 183 : } // boost