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