/src/libtorrent/src/chained_buffer.cpp
Line | Count | Source |
1 | | /* |
2 | | |
3 | | Copyright (c) 2011, 2014, 2016-2019, Arvid Norberg |
4 | | Copyright (c) 2016-2018, Alden Torres |
5 | | All rights reserved. |
6 | | |
7 | | Redistribution and use in source and binary forms, with or without |
8 | | modification, are permitted provided that the following conditions |
9 | | are met: |
10 | | |
11 | | * Redistributions of source code must retain the above copyright |
12 | | notice, this list of conditions and the following disclaimer. |
13 | | * Redistributions in binary form must reproduce the above copyright |
14 | | notice, this list of conditions and the following disclaimer in |
15 | | the documentation and/or other materials provided with the distribution. |
16 | | * Neither the name of the author nor the names of its |
17 | | contributors may be used to endorse or promote products derived |
18 | | from this software without specific prior written permission. |
19 | | |
20 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
21 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 | | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
24 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | | POSSIBILITY OF SUCH DAMAGE. |
31 | | |
32 | | */ |
33 | | |
34 | | #include "libtorrent/aux_/chained_buffer.hpp" |
35 | | #include "libtorrent/assert.hpp" |
36 | | |
37 | | #include <algorithm> // for copy |
38 | | |
39 | | namespace libtorrent { |
40 | | namespace aux { |
41 | | |
42 | | void chained_buffer::pop_front(int bytes_to_pop) |
43 | 0 | { |
44 | 0 | TORRENT_ASSERT(is_single_thread()); |
45 | 0 | TORRENT_ASSERT(!m_destructed); |
46 | 0 | TORRENT_ASSERT(bytes_to_pop <= m_bytes); |
47 | 0 | while (bytes_to_pop > 0 && !m_vec.empty()) |
48 | 0 | { |
49 | 0 | buffer_t& b = m_vec.front(); |
50 | 0 | if (b.used_size > bytes_to_pop) |
51 | 0 | { |
52 | 0 | b.buf += bytes_to_pop; |
53 | 0 | b.used_size -= bytes_to_pop; |
54 | 0 | b.size -= bytes_to_pop; |
55 | 0 | m_capacity -= bytes_to_pop; |
56 | 0 | m_bytes -= bytes_to_pop; |
57 | 0 | TORRENT_ASSERT(m_bytes <= m_capacity); |
58 | 0 | TORRENT_ASSERT(m_bytes >= 0); |
59 | 0 | TORRENT_ASSERT(m_capacity >= 0); |
60 | 0 | break; |
61 | 0 | } |
62 | | |
63 | 0 | b.destruct_holder(static_cast<void*>(&b.holder)); |
64 | 0 | m_bytes -= b.used_size; |
65 | 0 | m_capacity -= b.size; |
66 | 0 | bytes_to_pop -= b.used_size; |
67 | 0 | TORRENT_ASSERT(m_bytes >= 0); |
68 | 0 | TORRENT_ASSERT(m_capacity >= 0); |
69 | 0 | TORRENT_ASSERT(m_bytes <= m_capacity); |
70 | 0 | m_vec.pop_front(); |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | // returns the number of bytes available at the |
75 | | // end of the last chained buffer. |
76 | | int chained_buffer::space_in_last_buffer() |
77 | 0 | { |
78 | 0 | TORRENT_ASSERT(is_single_thread()); |
79 | 0 | TORRENT_ASSERT(!m_destructed); |
80 | 0 | if (m_vec.empty()) return 0; |
81 | 0 | buffer_t& b = m_vec.back(); |
82 | 0 | TORRENT_ASSERT(b.buf != nullptr); |
83 | 0 | return b.size - b.used_size; |
84 | 0 | } |
85 | | |
86 | | // tries to copy the given buffer to the end of the |
87 | | // last chained buffer. If there's not enough room |
88 | | // it returns nullptr |
89 | | char* chained_buffer::append(span<char const> buf) |
90 | 0 | { |
91 | 0 | TORRENT_ASSERT(is_single_thread()); |
92 | 0 | TORRENT_ASSERT(!m_destructed); |
93 | 0 | char* const insert = allocate_appendix(static_cast<int>(buf.size())); |
94 | 0 | if (insert == nullptr) return nullptr; |
95 | 0 | std::copy(buf.begin(), buf.end(), insert); |
96 | 0 | return insert; |
97 | 0 | } |
98 | | |
99 | | // tries to allocate memory from the end |
100 | | // of the last buffer. If there isn't |
101 | | // enough room, returns 0 |
102 | | char* chained_buffer::allocate_appendix(int const s) |
103 | 0 | { |
104 | 0 | TORRENT_ASSERT(is_single_thread()); |
105 | 0 | TORRENT_ASSERT(!m_destructed); |
106 | 0 | if (m_vec.empty()) return nullptr; |
107 | 0 | buffer_t& b = m_vec.back(); |
108 | 0 | TORRENT_ASSERT(b.buf != nullptr); |
109 | 0 | char* const insert = b.buf + b.used_size; |
110 | 0 | if (insert + s > b.buf + b.size) return nullptr; |
111 | 0 | b.used_size += s; |
112 | 0 | m_bytes += s; |
113 | 0 | TORRENT_ASSERT(m_bytes <= m_capacity); |
114 | 0 | return insert; |
115 | 0 | } |
116 | | |
117 | | span<boost::asio::const_buffer const> chained_buffer::build_iovec(int const to_send) |
118 | 0 | { |
119 | 0 | TORRENT_ASSERT(is_single_thread()); |
120 | 0 | TORRENT_ASSERT(!m_destructed); |
121 | 0 | m_tmp_vec.clear(); |
122 | 0 | build_vec(to_send, m_tmp_vec); |
123 | 0 | return m_tmp_vec; |
124 | 0 | } |
125 | | |
126 | | void chained_buffer::build_mutable_iovec(int bytes, std::vector<span<char>> &vec) |
127 | 0 | { |
128 | 0 | TORRENT_ASSERT(!m_destructed); |
129 | 0 | build_vec(bytes, vec); |
130 | 0 | } |
131 | | |
132 | | template <typename Buffer> |
133 | | void chained_buffer::build_vec(int bytes, std::vector<Buffer>& vec) |
134 | 0 | { |
135 | 0 | TORRENT_ASSERT(!m_destructed); |
136 | 0 | for (auto i = m_vec.begin(), end(m_vec.end()); bytes > 0 && i != end; ++i) |
137 | 0 | { |
138 | 0 | TORRENT_ASSERT(i->buf != nullptr); |
139 | 0 | if (i->used_size > bytes) |
140 | 0 | { |
141 | 0 | TORRENT_ASSERT(bytes > 0); |
142 | 0 | vec.emplace_back(i->buf, std::size_t(bytes)); |
143 | 0 | break; |
144 | 0 | } |
145 | 0 | TORRENT_ASSERT(i->used_size > 0); |
146 | 0 | vec.emplace_back(i->buf, std::size_t(i->used_size)); |
147 | 0 | bytes -= i->used_size; |
148 | 0 | } |
149 | 0 | } Unexecuted instantiation: void libtorrent::aux::chained_buffer::build_vec<boost::asio::const_buffer>(int, std::__1::vector<boost::asio::const_buffer, std::__1::allocator<boost::asio::const_buffer> >&) Unexecuted instantiation: void libtorrent::aux::chained_buffer::build_vec<libtorrent::span<char> >(int, std::__1::vector<libtorrent::span<char>, std::__1::allocator<libtorrent::span<char> > >&) |
150 | | |
151 | | void chained_buffer::clear() |
152 | 0 | { |
153 | 0 | TORRENT_ASSERT(!m_destructed); |
154 | 0 | for (auto& b : m_vec) |
155 | 0 | b.destruct_holder(static_cast<void*>(&b.holder)); |
156 | 0 | m_bytes = 0; |
157 | 0 | m_capacity = 0; |
158 | 0 | m_vec.clear(); |
159 | 0 | } |
160 | | |
161 | | chained_buffer::~chained_buffer() |
162 | 0 | { |
163 | 0 | TORRENT_ASSERT(!m_destructed); |
164 | 0 | TORRENT_ASSERT(is_single_thread()); |
165 | 0 | TORRENT_ASSERT(m_bytes >= 0); |
166 | 0 | TORRENT_ASSERT(m_capacity >= 0); |
167 | 0 | clear(); |
168 | 0 | #if TORRENT_USE_ASSERTS |
169 | 0 | m_destructed = true; |
170 | 0 | #endif |
171 | 0 | } |
172 | | |
173 | | } |
174 | | } |