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 748 : workspace:: 26 748 : ~workspace() 27 : { 28 748 : if(begin_) 29 : { 30 748 : clear(); 31 748 : delete[] begin_; 32 : } 33 748 : } 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 736 : workspace:: 64 : allocate( 65 : std::size_t n) 66 : { 67 : // Cannot be empty 68 736 : if(n == 0) 69 0 : detail::throw_invalid_argument(); 70 : 71 : // Already allocated 72 736 : if(begin_ != nullptr) 73 0 : detail::throw_logic_error(); 74 : 75 736 : begin_ = new unsigned char[n]; 76 736 : front_ = begin_; 77 736 : head_ = begin_ + n; 78 736 : back_ = head_; 79 736 : end_ = head_; 80 736 : } 81 : 82 : void 83 1501 : workspace:: 84 : clear() noexcept 85 : { 86 1501 : if(! begin_) 87 0 : return; 88 : 89 1501 : auto const end = 90 : reinterpret_cast< 91 : any const*>(back_); 92 1501 : auto p = 93 : reinterpret_cast< 94 : any const*>(head_); 95 1538 : while(p != end) 96 : { 97 37 : auto next = p->next; 98 37 : p->~any(); 99 37 : p = next; 100 : } 101 1501 : front_ = begin_; 102 1501 : head_ = end_; 103 1501 : back_ = end_; 104 : } 105 : 106 : void* 107 6 : 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 6 : if(n >= size()) 115 0 : detail::throw_length_error(); 116 : 117 6 : auto const p = front_; 118 6 : front_ += n ; 119 6 : return p; 120 : } 121 : 122 : void* 123 0 : workspace:: 124 : reserve_back( 125 : std::size_t n) 126 : { 127 : // can't reserve after acquire 128 0 : if(head_ != end_) 129 0 : detail::throw_logic_error(); 130 : 131 : // can't reserve twice 132 0 : if(back_ != end_) 133 0 : detail::throw_logic_error(); 134 : 135 : // over capacity 136 0 : std::size_t const lim = 137 0 : head_ - front_; 138 0 : if(n >= lim) 139 0 : detail::throw_length_error(); 140 : 141 0 : head_ -= n; 142 0 : back_ = head_; 143 0 : return back_; 144 : } 145 : 146 : // https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html 147 : void* 148 37 : workspace:: 149 : bump_down( 150 : std::size_t size, 151 : std::size_t align) 152 : { 153 37 : BOOST_ASSERT(align > 0); 154 37 : BOOST_ASSERT( 155 : (align & (align - 1)) == 0); 156 37 : BOOST_ASSERT(front_); 157 : 158 37 : auto ip0 = reinterpret_cast< 159 37 : std::uintptr_t>(front_); 160 37 : auto ip = reinterpret_cast< 161 37 : 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 37 : if(size > ip - ip0) 168 0 : detail::throw_bad_alloc(); 169 : 170 37 : ip -= size; 171 37 : 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 37 : if(ip < ip0) 178 0 : detail::throw_bad_alloc(); 179 : 180 37 : return reinterpret_cast<void*>(ip); 181 : } 182 : 183 : } // detail 184 : } // http_proto 185 : } // boost 186 : 187 : #endif