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