From: Guohui Wang Date: Fri, 29 Aug 2014 01:32:59 +0000 (-0700) Subject: add function to push data from another cursor X-Git-Tag: v0.22.0~345 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=cbfe1b0cae5a8f2efc7ddd03c5e120735e49d464;p=folly.git add function to push data from another cursor Summary: Add a function to Writable to push data from another cursor. Data in the input cursor could be in a buffer chain. Added test in IOBufCurosTest.cpp to test the new function. Test Plan: fbmake runtests; Reviewed By: simpkins@fb.com Subscribers: njormrod, net-systems@ FB internal diff: D1563209 Tasks: 4886058 Blame Revision: --- diff --git a/folly/io/Cursor.h b/folly/io/Cursor.h index 59fa0440..7963f193 100644 --- a/folly/io/Cursor.h +++ b/folly/io/Cursor.h @@ -428,6 +428,20 @@ class CursorBase { BufType* buffer_; }; +} //namespace detail + +class Cursor : public detail::CursorBase { + public: + explicit Cursor(const IOBuf* buf) + : detail::CursorBase(buf) {} + + template + explicit Cursor(const detail::CursorBase& cursor) + : detail::CursorBase(cursor) {} +}; + +namespace detail { + template class Writable { public: @@ -457,20 +471,47 @@ class Writable { 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 { - public: - explicit Cursor(const IOBuf* buf) - : detail::CursorBase(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 - explicit Cursor(const detail::CursorBase& cursor) - : detail::CursorBase(cursor) {} }; +} // namespace detail + enum class CursorAccess { PRIVATE, UNSHARE diff --git a/folly/io/test/IOBufCursorTest.cpp b/folly/io/test/IOBufCursorTest.cpp index 3ec3055e..58ad41d7 100644 --- a/folly/io/test/IOBufCursorTest.cpp +++ b/folly/io/test/IOBufCursorTest.cpp @@ -244,6 +244,52 @@ TEST(IOBuf, PullAndPeek) { } } +TEST(IOBuf, pushCursorData) { + unique_ptr iobuf1(IOBuf::create(20)); + iobuf1->append(15); + iobuf1->trimStart(5); + unique_ptr iobuf2(IOBuf::create(10)); + unique_ptr 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(1); + wcursor.writeBE(10); + wcursor.writeBE(20); + + // create a read buffer for the buffer chain + Cursor rcursor(iobuf1.get()); + EXPECT_EQ(1, rcursor.readBE()); + EXPECT_EQ(10, rcursor.readBE()); + EXPECT_EQ(20, rcursor.readBE()); + EXPECT_EQ(0, rcursor.totalLength()); + rcursor.reset(iobuf1.get()); + EXPECT_EQ(20, rcursor.totalLength()); + + // create another write buffer + unique_ptr 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()); + EXPECT_EQ(10, rcursor2.readBE()); + EXPECT_EQ(20, rcursor2.readBE()); + +} + TEST(IOBuf, Gather) { std::unique_ptr iobuf1(IOBuf::create(10)); append(iobuf1, "he");