BufType* buffer_;
};
+} //namespace detail
+
+class Cursor : public detail::CursorBase<Cursor, const IOBuf> {
+ public:
+ explicit Cursor(const IOBuf* buf)
+ : detail::CursorBase<Cursor, const IOBuf>(buf) {}
+
+ template <class OtherDerived, class OtherBuf>
+ explicit Cursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
+ : detail::CursorBase<Cursor, const IOBuf>(cursor) {}
+};
+
+namespace detail {
+
template <class Derived>
class Writable {
public:
throw std::out_of_range("overflow");
}
}
-};
-} // namespace detail
+ /**
+ * push len bytes of data from input cursor, data could be in an IOBuf chain.
+ * If input cursor contains less than len bytes, or this cursor has less than
+ * len bytes writable space, an out_of_range exception will be thrown.
+ */
+ void push(Cursor cursor, size_t len) {
+ if (this->pushAtMost(cursor, len) != len) {
+ throw std::out_of_range("overflow");
+ }
+ }
-class Cursor : public detail::CursorBase<Cursor, const IOBuf> {
- public:
- explicit Cursor(const IOBuf* buf)
- : detail::CursorBase<Cursor, const IOBuf>(buf) {}
+ size_t pushAtMost(Cursor cursor, size_t len) {
+ size_t written = 0;
+ for(;;) {
+ auto currentBuffer = cursor.peek();
+ const uint8_t* crtData = currentBuffer.first;
+ size_t available = currentBuffer.second;
+ if (available == 0) {
+ // end of buffer chain
+ return written;
+ }
+ // all data is in current buffer
+ if (available >= len) {
+ this->push(crtData, len);
+ cursor.skip(len);
+ return written + len;
+ }
+
+ // write the whole current IOBuf
+ this->push(crtData, available);
+ cursor.skip(available);
+ written += available;
+ len -= available;
+ }
+ }
- template <class OtherDerived, class OtherBuf>
- explicit Cursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
- : detail::CursorBase<Cursor, const IOBuf>(cursor) {}
};
+} // namespace detail
+
enum class CursorAccess {
PRIVATE,
UNSHARE
}
}
+TEST(IOBuf, pushCursorData) {
+ unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
+ iobuf1->append(15);
+ iobuf1->trimStart(5);
+ unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
+ unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
+ iobuf3->append(10);
+
+ iobuf1->prependChain(std::move(iobuf2));
+ iobuf1->prependChain(std::move(iobuf3));
+ EXPECT_TRUE(iobuf1->isChained());
+
+ //write 20 bytes to the buffer chain
+ RWPrivateCursor wcursor(iobuf1.get());
+ wcursor.writeBE<uint64_t>(1);
+ wcursor.writeBE<uint64_t>(10);
+ wcursor.writeBE<uint32_t>(20);
+
+ // create a read buffer for the buffer chain
+ Cursor rcursor(iobuf1.get());
+ EXPECT_EQ(1, rcursor.readBE<uint64_t>());
+ EXPECT_EQ(10, rcursor.readBE<uint64_t>());
+ EXPECT_EQ(20, rcursor.readBE<uint32_t>());
+ EXPECT_EQ(0, rcursor.totalLength());
+ rcursor.reset(iobuf1.get());
+ EXPECT_EQ(20, rcursor.totalLength());
+
+ // create another write buffer
+ unique_ptr<IOBuf> iobuf4(IOBuf::create(30));
+ iobuf4->append(30);
+ RWPrivateCursor wcursor2(iobuf4.get());
+ // write buffer chain data into it, now wcursor2 should only
+ // have 10 bytes writable space
+ wcursor2.push(rcursor, 20);
+ EXPECT_EQ(wcursor2.totalLength(), 10);
+ // write again with not enough space in rcursor
+ EXPECT_THROW(wcursor2.push(rcursor, 20), std::out_of_range);
+
+ // create a read cursor to check iobuf3 data back
+ Cursor rcursor2(iobuf4.get());
+ EXPECT_EQ(1, rcursor2.readBE<uint64_t>());
+ EXPECT_EQ(10, rcursor2.readBE<uint64_t>());
+ EXPECT_EQ(20, rcursor2.readBE<uint32_t>());
+
+}
+
TEST(IOBuf, Gather) {
std::unique_ptr<IOBuf> iobuf1(IOBuf::create(10));
append(iobuf1, "he");