buffer::list::iterator_impl<is_const>::iterator_impl(const buffer::list::iterator& i)
: iterator_impl<is_const>(i.bl, i.off, i.p, i.p_off) {}
+#ifdef BL_BACKWARD_COMPAT
+ /// The backward iteration over is bufferlist is DEPRECATED!
+ /// The old int-taking variant of advance() is solely for compatibility.
template<bool is_const>
void buffer::list::iterator_impl<is_const>::advance(int o)
{
- //cout << this << " advance " << o << " from " << off << " (p_off " << p_off << " in " << p->length() << ")" << std::endl;
- if (o > 0) {
- p_off += o;
- while (p_off > 0) {
- if (p == ls->end())
- throw end_of_buffer();
- if (p_off >= p->length()) {
- // skip this buffer
- p_off -= p->length();
- p++;
- } else {
- // somewhere in this buffer!
- break;
- }
- }
- off += o;
+ seek(off + o);
+ }
+#endif // BL_BACKWARD_COMPAT
+
+ template<bool is_const>
+ void buffer::list::iterator_impl<is_const>::advance(unsigned o)
+ {
+ //cout << this << " advance " << o << " from " << off
+ // << " (p_off " << p_off << " in " << p->length() << ")"
+ // << std::endl;
+
+ p_off += o;
+
+ if (!o) {
return;
}
- while (o < 0) {
- if (p_off) {
- unsigned d = -o;
- if (d > p_off)
- d = p_off;
- p_off -= d;
- off -= d;
- o += d;
- } else if (off > 0) {
- ceph_assert(p != ls->begin());
- p--;
- p_off = p->length();
+ while (p_off > 0) {
+ if (p == ls->end())
+ throw end_of_buffer();
+ if (p_off >= p->length()) {
+ // skip this buffer
+ p_off -= p->length();
+ p++;
} else {
- throw end_of_buffer();
+ // somewhere in this buffer!
+ break;
}
}
+ off += o;
}
template<bool is_const>
{
if (p == ls->end())
throw end_of_buffer();
- advance(1);
+ advance(1u);
return *this;
}
: iterator_impl(l, o, ip, po)
{}
+#ifdef BL_BACKWARD_COMPAT
+ /// The backward iteration over is bufferlist is DEPRECATED!
+ /// The old int-taking variant of advance() is solely for compatibility.
void buffer::list::iterator::advance(int o)
+ {
+ seek(off + o);
+ }
+#endif // BL_BACKWARD_COMPAT
+
+ void buffer::list::iterator::advance(unsigned o)
{
buffer::list::iterator_impl<false>::advance(o);
}
//return off == bl->length();
}
+#ifdef BL_BACKWARD_COMPAT
void advance(int o);
+#else
+ void advance(int o) = delete;
+#endif // BL_BACKWARD_COMPAT
+
+ void advance(unsigned o);
+ void advance(size_t o) { advance(static_cast<unsigned>(o)); }
void seek(unsigned o);
char operator*() const;
iterator_impl& operator++();
iterator(bl_t *l, unsigned o=0);
iterator(bl_t *l, unsigned o, list_iter_t ip, unsigned po);
+#ifdef BL_BACKWARD_COMPAT
void advance(int o);
+#else
+ void advance(int o) = delete;
+#endif // BL_BACKWARD_COMPAT
+
+ void advance(unsigned o);
+ void advance(size_t o) { advance(static_cast<unsigned>(o)); }
+
void seek(unsigned o);
using iterator_impl<false>::operator*;
char operator*();
t.copy_shallow(remaining, tmp);
auto cp = std::cbegin(tmp);
traits::decode(o, cp);
- p.advance((ssize_t)cp.get_offset());
+ p.advance(cp.get_offset());
}
}
t.copy_shallow(p.get_bl().length() - p.get_off(), tmp);
auto cp = std::cbegin(tmp);
traits::decode(o, cp);
- p.advance((ssize_t)cp.get_offset());
+ p.advance(cp.get_offset());
}
// nohead variants
t.copy_shallow(p.get_bl().length() - p.get_off(), tmp);
auto cp = std::cbegin(tmp);
traits::decode_nohead(num, o, cp);
- p.advance((ssize_t)cp.get_offset());
+ p.advance(cp.get_offset());
}
}
* @param v current (code) version of the encoding
* @param compat oldest code version that can decode it
* @param bl bufferlist to encode to
+ *
+ * NOTE: to not advance() backward, we snapshot the end of bufferlist
+ * in a given moment, and then rely on copy_in()'s ability to rewind:
+ *
+ * void buffer::list::iterator::copy_in(...)
+ * {
+ * // copy
+ * if (p == ls->end())
+ * seek(off);
+ *
+ * // ...
+ * }
+ *
+ * This can be quite costly, so next commit is expected to remedy.
*/
#define ENCODE_START(v, compat, bl) \
using ::ceph::encode; \
__u8 struct_v = v, struct_compat = compat; \
encode(struct_v, (bl)); \
- encode(struct_compat, (bl)); \
::ceph::buffer::list::iterator struct_compat_it = (bl).end(); \
- struct_compat_it.advance(-1); \
+ encode(struct_compat, (bl)); \
ceph_le32 struct_len; \
struct_len = 0; \
- encode(struct_len, (bl)); \
::ceph::buffer::list::iterator struct_len_it = (bl).end(); \
- struct_len_it.advance(-4); \
+ encode(struct_len, (bl)); \
do {
/**
if (v < struct_compat) \
throw buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v, struct_compat)); \
} else if (skip_v) { \
- if ((int)bl.get_remaining() < skip_v) \
+ if (bl.get_remaining() < skip_v) \
throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
bl.advance(skip_v); \
} \
* @param bl bufferlist::iterator containing the encoded data
*/
#define DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, bl) \
- __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 0, bl)
+ __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 0u, bl)
/**
* start a decoding block with legacy support for older encoding schemes
* @param bl bufferlist::iterator containing the encoded data
*/
#define DECODE_START_LEGACY_COMPAT_LEN_32(v, compatv, lenv, bl) \
- __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 3, bl)
+ __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 3u, bl)
#define DECODE_START_LEGACY_COMPAT_LEN_16(v, compatv, lenv, bl) \
- __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 1, bl)
+ __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 1u, bl)
/**
* finish decode block
using ceph::encode;
if (xattr_version) {
ceph_le32 xbl_len;
+ auto xbl_len_it = bl.end();
xbl_len = sizeof(__u32);
encode(xbl_len, bl);
-
- auto xbl_len_it = bl.end();
- xbl_len_it.advance(-4);
if (pxattrs)
encode(*pxattrs, bl);
else
if (got < 0)
goto out_dethrottle;
if (got > 0) {
- blp.advance(got);
+ blp.advance(static_cast<size_t>(got));
data.append(bp, 0, got);
offset += got;
left -= got;
void bluestore_bdev_label_t::decode(bufferlist::const_iterator& p)
{
- p.advance(60); // see above
+ p.advance(60u); // see above
DECODE_START(2, p);
decode(osd_uuid, p);
decode(size, p);
decode(v, bl);
if (v < 2) { // normally 0, but conceivably 1
// decode old header_t struct (pre v0.40).
- bl.advance(4); // skip __u32 flags (it was unused by any old code)
+ bl.advance(4u); // skip __u32 flags (it was unused by any old code)
flags = 0;
uint64_t tfsid;
decode(tfsid, bl);
ENCODE_FINISH(bl); // osd-only data
}
- encode((uint32_t)0, bl); // dummy inc_crc
crc_it = bl.end();
- crc_it.advance(-4);
+ encode((uint32_t)0, bl); // dummy inc_crc
tail_offset = bl.length();
encode(full_crc, bl);
DECODE_START_LEGACY_COMPAT_LEN(8, 7, 7, bl); // wrapper
if (struct_v < 7) {
- int struct_v_size = sizeof(struct_v);
- bl.advance(-struct_v_size);
+ bl.seek(start_offset);
decode_classic(bl);
encode_features = 0;
if (struct_v >= 6)
ENCODE_FINISH(bl); // osd-only data
}
- encode((uint32_t)0, bl); // dummy crc
crc_it = bl.end();
- crc_it.advance(-4);
+ encode((uint32_t)0, bl); // dummy crc
tail_offset = bl.length();
ENCODE_FINISH(bl); // meta-encoding wrapper
DECODE_START_LEGACY_COMPAT_LEN(8, 7, 7, bl); // wrapper
if (struct_v < 7) {
- int struct_v_size = sizeof(struct_v);
- bl.advance(-struct_v_size);
+ bl.seek(start_offset);
decode_classic(bl);
return;
}
{
DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl);
decode(seq, bl);
- bl.advance(1); // skip legacy head_exists (always true)
+ bl.advance(1u); // skip legacy head_exists (always true)
decode(snaps, bl);
decode(clones, bl);
decode(clone_overlap, bl);
EXPECT_EQ('B', *i);
EXPECT_EQ('C', *j);
bl.c_str()[1] = 'X';
+#ifdef BL_BACKWARD_COMPAT
j.advance(-1);
EXPECT_EQ('X', *j);
+#endif // BL_BACKWARD_COMPAT
}
//
{
bufferlist::iterator i(&bl);
- EXPECT_THROW(i.advance(200), buffer::end_of_buffer);
+ EXPECT_THROW(i.advance(200u), buffer::end_of_buffer);
}
+#ifdef BL_BACKWARD_COMPAT
{
bufferlist::iterator i(&bl);
EXPECT_THROW(i.advance(-1), buffer::end_of_buffer);
}
+#endif // BL_BACKWARD_COMPAT
{
bufferlist::iterator i(&bl);
EXPECT_EQ('A', *i);
- i.advance(1);
+ i.advance(1u);
EXPECT_EQ('B', *i);
- i.advance(3);
+ i.advance(3u);
EXPECT_EQ('E', *i);
+#ifdef BL_BACKWARD_COMPAT
i.advance(-3);
EXPECT_EQ('B', *i);
i.advance(-1);
EXPECT_EQ('A', *i);
+#endif // BL_BACKWARD_COMPAT
}
}
bl.append(c);
const char *ptr;
bufferlist::iterator p = bl.begin();
- ASSERT_EQ(3u, p.get_ptr_and_advance(11, &ptr));
+ ASSERT_EQ(3u, p.get_ptr_and_advance(11u, &ptr));
ASSERT_EQ(bl.length() - 3u, p.get_remaining());
ASSERT_EQ(0, memcmp(ptr, "one", 3));
- ASSERT_EQ(2u, p.get_ptr_and_advance(2, &ptr));
+ ASSERT_EQ(2u, p.get_ptr_and_advance(2u, &ptr));
ASSERT_EQ(0, memcmp(ptr, "tw", 2));
- ASSERT_EQ(1u, p.get_ptr_and_advance(4, &ptr));
+ ASSERT_EQ(1u, p.get_ptr_and_advance(4u, &ptr));
ASSERT_EQ(0, memcmp(ptr, "o", 1));
- ASSERT_EQ(5u, p.get_ptr_and_advance(5, &ptr));
+ ASSERT_EQ(5u, p.get_ptr_and_advance(5u, &ptr));
ASSERT_EQ(0, memcmp(ptr, "three", 5));
ASSERT_EQ(0u, p.get_remaining());
}
bl3.append(s.substr(98, 55));
it = bl1.begin();
- it.advance(98);
+ it.advance(98u);
ASSERT_EQ(bl3.crc32c(0), it.crc32c(55, 0));
ASSERT_EQ(4u, it.get_remaining());
bl3.clear();
bl3.append(s.substr(98 + 55));
it = bl1.begin();
- it.advance(98 + 55);
+ it.advance(98u + 55u);
ASSERT_EQ(bl3.crc32c(0), it.crc32c(10, 0));
ASSERT_EQ(0u, it.get_remaining());
}
{
bufferlist::iterator i(&bl);
EXPECT_EQ('A', *i);
- EXPECT_THROW(i.advance(200), buffer::end_of_buffer);
+ EXPECT_THROW(i.advance(200u), buffer::end_of_buffer);
EXPECT_THROW(*i, buffer::end_of_buffer);
}
}
//
// demonstrates that it seeks back to offset if p == ls->end()
//
- EXPECT_THROW(i.advance(200), buffer::end_of_buffer);
+ EXPECT_THROW(i.advance(200u), buffer::end_of_buffer);
i.copy(2, copy);
EXPECT_EQ(0, ::memcmp(copy, expected, 2));
EXPECT_EQ('X', copy[2]);
//
// demonstrates that it seeks back to offset if p == ls->end()
//
- EXPECT_THROW(i.advance(200), buffer::end_of_buffer);
+ EXPECT_THROW(i.advance(200u), buffer::end_of_buffer);
i.copy(2, copy);
EXPECT_EQ(0, ::memcmp(copy.c_str(), expected, 2));
i.seek(0);
//
// demonstrates that it seeks back to offset if p == ls->end()
//
- EXPECT_THROW(i.advance(200), buffer::end_of_buffer);
+ EXPECT_THROW(i.advance(200u), buffer::end_of_buffer);
i.copy_all(copy);
EXPECT_EQ('A', copy[0]);
EXPECT_EQ('B', copy[1]);
//
// demonstrates that it seeks back to offset if p == ls->end()
//
- EXPECT_THROW(i.advance(200), buffer::end_of_buffer);
+ EXPECT_THROW(i.advance(200u), buffer::end_of_buffer);
i.copy(2, copy);
EXPECT_EQ(0, ::memcmp(copy.c_str(), expected, 2));
i.seek(0);
//
// demonstrates that it seeks back to offset if p == ls->end()
//
- EXPECT_THROW(i.advance(200), buffer::end_of_buffer);
+ EXPECT_THROW(i.advance(200u), buffer::end_of_buffer);
const char *expected = "ABC";
i.copy_in(3, expected);
EXPECT_EQ(0, ::memcmp(bl.c_str(), expected, 3));
//
// demonstrates that it seeks back to offset if p == ls->end()
//
- EXPECT_THROW(i.advance(200), buffer::end_of_buffer);
+ EXPECT_THROW(i.advance(200u), buffer::end_of_buffer);
bufferlist expected;
expected.append("ABC", 3);
i.copy_in(3, expected);
TEST(BufferList, end) {
bufferlist bl;
- bl.append("ABC");
+ bl.append("AB");
bufferlist::iterator i = bl.end();
- i.advance(-1);
- EXPECT_EQ('C', *i);
+ bl.append("C");
+ EXPECT_EQ('C', bl[i.get_off()]);
}
TEST(BufferList, copy) {