fixes bug where priorities where lost when force-rechecking.
[libtorrent.git] / include / libtorrent / chained_buffer.hpp
blobcaf2e89beec88f5f7e9a38114861951408624d28
1 /*
3 Copyright (c) 2007, Arvid Norberg
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
33 #ifndef TORRENT_CHAINED_BUFFER_HPP_INCLUDED
34 #define TORRENT_CHAINED_BUFFER_HPP_INCLUDED
36 #include <boost/function.hpp>
37 #include <boost/version.hpp>
38 #if BOOST_VERSION < 103500
39 #include <asio/buffer.hpp>
40 #else
41 #include <boost/asio/buffer.hpp>
42 #endif
43 #include <list>
44 #include <cstring>
46 namespace libtorrent
48 #if BOOST_VERSION >= 103500
49 namespace asio = boost::asio;
50 #endif
51 struct chained_buffer
53 chained_buffer(): m_bytes(0), m_capacity(0) {}
55 struct buffer_t
57 boost::function<void(char*)> free; // destructs the buffer
58 char* buf; // the first byte of the buffer
59 int size; // the total size of the buffer
61 char* start; // the first byte to send/receive in the buffer
62 int used_size; // this is the number of bytes to send/receive
65 bool empty() const { return m_bytes == 0; }
66 int size() const { return m_bytes; }
67 int capacity() const { return m_capacity; }
69 void pop_front(int bytes_to_pop)
71 TORRENT_ASSERT(bytes_to_pop <= m_bytes);
72 while (bytes_to_pop > 0 && !m_vec.empty())
74 buffer_t& b = m_vec.front();
75 if (b.used_size > bytes_to_pop)
77 b.start += bytes_to_pop;
78 b.used_size -= bytes_to_pop;
79 m_bytes -= bytes_to_pop;
80 TORRENT_ASSERT(m_bytes <= m_capacity);
81 TORRENT_ASSERT(m_bytes >= 0);
82 TORRENT_ASSERT(m_capacity >= 0);
83 break;
86 b.free(b.buf);
87 m_bytes -= b.used_size;
88 m_capacity -= b.size;
89 bytes_to_pop -= b.used_size;
90 TORRENT_ASSERT(m_bytes >= 0);
91 TORRENT_ASSERT(m_capacity >= 0);
92 TORRENT_ASSERT(m_bytes <= m_capacity);
93 m_vec.pop_front();
97 template <class D>
98 void append_buffer(char* buffer, int size, int used_size, D const& destructor)
100 TORRENT_ASSERT(size >= used_size);
101 buffer_t b;
102 b.buf = buffer;
103 b.size = size;
104 b.start = buffer;
105 b.used_size = used_size;
106 b.free = destructor;
107 m_vec.push_back(b);
109 m_bytes += used_size;
110 m_capacity += size;
111 TORRENT_ASSERT(m_bytes <= m_capacity);
114 // returns the number of bytes available at the
115 // end of the last chained buffer.
116 int space_in_last_buffer()
118 if (m_vec.empty()) return 0;
119 buffer_t& b = m_vec.back();
120 return b.size - b.used_size - (b.start - b.buf);
123 // tries to copy the given buffer to the end of the
124 // last chained buffer. If there's not enough room
125 // it returns false
126 bool append(char const* buf, int size)
128 char* insert = allocate_appendix(size);
129 if (insert == 0) return false;
130 std::memcpy(insert, buf, size);
131 return true;
134 // tries to allocate memory from the end
135 // of the last buffer. If there isn't
136 // enough room, returns 0
137 char* allocate_appendix(int size)
139 if (m_vec.empty()) return 0;
140 buffer_t& b = m_vec.back();
141 char* insert = b.start + b.used_size;
142 if (insert + size > b.buf + b.size) return 0;
143 b.used_size += size;
144 m_bytes += size;
145 TORRENT_ASSERT(m_bytes <= m_capacity);
146 return insert;
149 std::list<asio::const_buffer> const& build_iovec(int to_send)
151 m_tmp_vec.clear();
153 for (std::list<buffer_t>::iterator i = m_vec.begin()
154 , end(m_vec.end()); to_send > 0 && i != end; ++i)
156 if (i->used_size > to_send)
158 TORRENT_ASSERT(to_send > 0);
159 m_tmp_vec.push_back(asio::const_buffer(i->start, to_send));
160 break;
162 TORRENT_ASSERT(i->used_size > 0);
163 m_tmp_vec.push_back(asio::const_buffer(i->start, i->used_size));
164 to_send -= i->used_size;
166 return m_tmp_vec;
169 ~chained_buffer()
171 for (std::list<buffer_t>::iterator i = m_vec.begin()
172 , end(m_vec.end()); i != end; ++i)
174 i->free(i->buf);
178 private:
180 // this is the list of all the buffers we want to
181 // send
182 std::list<buffer_t> m_vec;
184 // this is the number of bytes in the send buf.
185 // this will always be equal to the sum of the
186 // size of all buffers in vec
187 int m_bytes;
189 // the total size of all buffers in the chain
190 // including unused space
191 int m_capacity;
193 // this is the vector of buffers used when
194 // invoking the async write call
195 std::list<asio::const_buffer> m_tmp_vec;
199 #endif