}
}
- buffer::list::iterator buffer::list::append_hole(const unsigned len)
+ buffer::list::contiguous_filler buffer::list::append_hole(const unsigned len)
{
if (unlikely(append_buffer.unused_tail_length() < len)) {
// make a new append_buffer. fill out a complete page, factoring in
append_buffer.set_length(append_buffer.length() + len);
append(append_buffer, append_buffer.length() - len, len);
- const auto lastbuf = std::prev(std::end(_buffers));
- return { this, length() - len, lastbuf, lastbuf->length() - len };
+ return { std::prev(std::end(_buffers))->end_c_str() - len };
}
void buffer::list::prepend_zero(unsigned len)
return contiguous_appender(this, len, deep);
}
+ class contiguous_filler {
+ friend buffer::list;
+ char* pos;
+
+ contiguous_filler(char* const pos) : pos(pos) {}
+
+ public:
+ void copy_in(const unsigned len, const char* const src) {
+ memcpy(pos, src, len);
+ pos += len;
+ }
+ };
+ // The contiguous_filler is supposed to be not costlier than a single
+ // pointer. Keep it dumb, please.
+ static_assert(sizeof(contiguous_filler) == sizeof(char*));
+
class page_aligned_appender {
bufferlist *pbl;
unsigned min_alloc;
void append(const ptr& bp, unsigned off, unsigned len);
void append(const list& bl);
void append(std::istream& in);
- iterator append_hole(unsigned len);
+ contiguous_filler append_hole(unsigned len);
void append_zero(unsigned len);
void prepend_zero(unsigned len);
*
*/
#define ENCODE_START(v, compat, bl) \
- using ::ceph::encode; \
- __u8 struct_v = v, struct_compat = compat; \
+ __u8 struct_v = v; \
+ __u8 struct_compat = compat; \
ceph_le32 struct_len; \
- encode(struct_v, (bl)); \
- ::ceph::buffer::list::iterator struct_compat_it = \
- (bl).append_hole(sizeof(struct_compat)); \
- ::ceph::buffer::list::iterator struct_len_it = \
- (bl).append_hole(sizeof(struct_len)); \
+ auto filler = (bl).append_hole(sizeof(struct_v) + \
+ sizeof(struct_compat) + sizeof(struct_len)); \
+ const auto starting_bl_len = (bl).length(); \
+ using ::ceph::encode; \
do {
/**
* @param bl bufferlist we were encoding to
* @param new_struct_compat struct-compat value to use
*/
-#define ENCODE_FINISH_NEW_COMPAT(bl, new_struct_compat) \
- } while (false); \
- struct_len = (bl).length() - struct_len_it.get_off() - sizeof(struct_len); \
- struct_len_it.copy_in(4, (char *)&struct_len); \
- if (new_struct_compat) { \
- struct_compat = new_struct_compat; \
- } \
- struct_compat_it.copy_in(1, (char *)&struct_compat);
+#define ENCODE_FINISH_NEW_COMPAT(bl, new_struct_compat) \
+ } while (false); \
+ if (new_struct_compat) { \
+ struct_compat = new_struct_compat; \
+ } \
+ struct_len = (bl).length() - starting_bl_len; \
+ filler.copy_in(sizeof(struct_v), (char *)&struct_v); \
+ filler.copy_in(sizeof(struct_compat), \
+ (char *)&struct_compat); \
+ filler.copy_in(sizeof(struct_len), (char *)&struct_len);
#define ENCODE_FINISH(bl) ENCODE_FINISH_NEW_COMPAT(bl, 0)
TEST(BufferList, append_hole) {
{
bufferlist bl;
- auto iter = bl.append_hole(1);
+ auto filler = bl.append_hole(1);
EXPECT_EQ((unsigned)1, bl.get_num_buffers());
EXPECT_EQ((unsigned)1, bl.length());
EXPECT_EQ((unsigned)3, bl.length());
const char a = 'A';
- EXPECT_EQ((unsigned)2, bl.length() - iter.get_off() - sizeof(a));
- iter.copy_in((unsigned)1, &a);
+ filler.copy_in((unsigned)1, &a);
EXPECT_EQ((unsigned)3, bl.length());
EXPECT_EQ(0, ::memcmp("ABC", bl.c_str(), 3));
EXPECT_EQ((unsigned)1, bl.get_num_buffers());
EXPECT_EQ((unsigned)1, bl.length());
- auto iter = bl.append_hole(1);
+ auto filler = bl.append_hole(1);
EXPECT_EQ((unsigned)1, bl.get_num_buffers());
EXPECT_EQ((unsigned)2, bl.length());
EXPECT_EQ((unsigned)3, bl.length());
const char b = 'B';
- EXPECT_EQ((unsigned)1, bl.length() - iter.get_off() - sizeof(b));
- iter.copy_in((unsigned)1, &b);
+ filler.copy_in((unsigned)1, &b);
EXPECT_EQ((unsigned)3, bl.length());
EXPECT_EQ(0, ::memcmp("ABC", bl.c_str(), 3));