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 : /* Layout 22 : 23 : The buffer is laid out thusly: 24 : 25 : base_ begin_ head_ end_ 26 : 27 : |<- reserved ->|<- unused ->|<- acquired ->| 28 : */ 29 : workspace:: 30 : any:: 31 : ~any() = default; 32 : 33 756 : workspace:: 34 756 : ~workspace() 35 : { 36 756 : if(base_) 37 : { 38 756 : clear(); 39 756 : delete[] base_; 40 : } 41 756 : } 42 : 43 11 : workspace:: 44 : workspace( 45 11 : std::size_t n) 46 11 : : base_(new unsigned char[n]) 47 11 : , begin_(base_) 48 11 : , head_(base_ + n) 49 11 : , end_(head_) 50 : { 51 11 : } 52 : 53 0 : workspace:: 54 : workspace( 55 0 : workspace&& other) noexcept 56 0 : : base_(other.base_) 57 0 : , begin_(other.begin_) 58 0 : , head_(other.end_) 59 0 : , end_(other.end_) 60 : { 61 0 : other.base_ = nullptr; 62 0 : other.begin_ = nullptr; 63 0 : other.head_ = nullptr; 64 0 : other.end_ = nullptr; 65 0 : } 66 : 67 : void 68 745 : workspace:: 69 : allocate( 70 : std::size_t n) 71 : { 72 : // n == 0 73 745 : if(n == 0) 74 0 : detail::throw_invalid_argument(); 75 : 76 : // this->size() > 0 77 745 : if(base_ != nullptr) 78 0 : detail::throw_logic_error(); 79 : 80 745 : base_ = new unsigned char[n]; 81 745 : begin_ = base_; 82 745 : head_ = base_ + n; 83 745 : end_ = head_; 84 745 : } 85 : 86 : void 87 1543 : workspace:: 88 : clear() noexcept 89 : { 90 1543 : BOOST_ASSERT(begin_); 91 : 92 1543 : auto const end = 93 : reinterpret_cast< 94 : any const*>(end_); 95 1543 : auto p = 96 : reinterpret_cast< 97 : any const*>(head_); 98 1580 : while(p != end) 99 : { 100 37 : auto next = p->next; 101 37 : p->~any(); 102 37 : p = next; 103 : } 104 1543 : head_ = end_; 105 1543 : begin_ = base_; 106 1543 : } 107 : 108 : void 109 6 : workspace:: 110 : reserve(std::size_t n) 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 : base_ += n ; 118 6 : } 119 : 120 : // https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html 121 : void* 122 37 : workspace:: 123 : bump_down( 124 : std::size_t size, 125 : std::size_t align) 126 : { 127 37 : BOOST_ASSERT(align > 0); 128 37 : BOOST_ASSERT( 129 : (align & (align - 1)) == 0); 130 37 : BOOST_ASSERT(begin_); 131 : 132 37 : auto ip0 = reinterpret_cast< 133 37 : std::uintptr_t>(begin_); 134 37 : auto ip = reinterpret_cast< 135 37 : std::uintptr_t>(head_); 136 : 137 : // If you get an exception here, it 138 : // means that a buffer was too small 139 : // for your workload. Increase the 140 : // buffer size. 141 37 : if(size > ip - ip0) 142 0 : detail::throw_bad_alloc(); 143 : 144 37 : ip -= size; 145 37 : ip &= ~(align - 1); 146 : 147 : // If you get an exception here, it 148 : // means that a buffer was too small 149 : // for your workload. Increase the 150 : // buffer size. 151 37 : if(ip < ip0) 152 0 : detail::throw_bad_alloc(); 153 : 154 37 : return reinterpret_cast<void*>(ip); 155 : } 156 : 157 : } // detail 158 : } // http_proto 159 : } // boost 160 : 161 : #endif