From: Adam Simpkins Date: Thu, 12 Mar 2015 23:00:31 +0000 (-0700) Subject: add Cursor::isAtEnd() X-Git-Tag: v0.31.0~12 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=commitdiff_plain;h=efca08ae72f06fb6d2ba6941600f459d3e7bcc62 add Cursor::isAtEnd() Summary: Add a helper method to efficiently check if the cursor is at the end of the IOBuf chain. This is equivalent to (cursor.totalLength() > 0), but it doesn't need to walk the entire chain just to tell if it is at the end or not. Test Plan: Updated the unit tests to contain some checks for isAtEnd(). Reviewed By: jasmeetbagga@fb.com Subscribers: trunkagent, doug, net-systems@, exa, folly-diffs@, yfeldblum FB internal diff: D1875345 Signature: t1:1875345:1425006512:49ac246fd0ac7937fdcd6cf1359a841f048c444e --- diff --git a/folly/io/Cursor.h b/folly/io/Cursor.h index 8bb11bdc..2aa4227f 100644 --- a/folly/io/Cursor.h +++ b/folly/io/Cursor.h @@ -108,6 +108,30 @@ class CursorBase { return end - *this; } + /* + * Return true if the cursor is at the end of the entire IOBuf chain. + */ + bool isAtEnd() const { + // Check for the simple cases first. + if (offset_ != crtBuf_->length()) { + return false; + } + if (crtBuf_ == buffer_->prev()) { + return true; + } + // We are at the end of a buffer, but it isn't the last buffer. + // We might still be at the end if the remaining buffers in the chain are + // empty. + const IOBuf* buf = crtBuf_->next();; + while (buf != buffer_) { + if (buf->length() > 0) { + return false; + } + buf = buf->next(); + } + return true; + } + Derived& operator+=(size_t offset) { Derived* p = static_cast(this); p->skip(offset); diff --git a/folly/io/test/IOBufCursorTest.cpp b/folly/io/test/IOBufCursorTest.cpp index 9cd061d5..3d1a4014 100644 --- a/folly/io/test/IOBufCursorTest.cpp +++ b/folly/io/test/IOBufCursorTest.cpp @@ -263,9 +263,11 @@ TEST(IOBuf, pushCursorData) { //write 20 bytes to the buffer chain RWPrivateCursor wcursor(iobuf1.get()); + EXPECT_FALSE(wcursor.isAtEnd()); wcursor.writeBE(1); wcursor.writeBE(10); wcursor.writeBE(20); + EXPECT_TRUE(wcursor.isAtEnd()); // create a read buffer for the buffer chain Cursor rcursor(iobuf1.get()); @@ -320,6 +322,7 @@ TEST(IOBuf, Gather) { cursor.gatherAtMost(10); EXPECT_EQ(8, cursor.length()); EXPECT_EQ(8, cursor.totalLength()); + EXPECT_FALSE(cursor.isAtEnd()); EXPECT_EQ("lo world", folly::StringPiece(reinterpret_cast(cursor.data()), cursor.length())); @@ -504,10 +507,13 @@ TEST(IOBuf, CursorOperators) { Cursor curs1(chain1.get()); EXPECT_EQ(0, curs1 - chain1.get()); + EXPECT_FALSE(curs1.isAtEnd()); curs1.skip(3); EXPECT_EQ(3, curs1 - chain1.get()); + EXPECT_FALSE(curs1.isAtEnd()); curs1.skip(7); EXPECT_EQ(10, curs1 - chain1.get()); + EXPECT_TRUE(curs1.isAtEnd()); Cursor curs2(chain1.get()); EXPECT_EQ(0, curs2 - chain1.get()); @@ -551,6 +557,26 @@ TEST(IOBuf, CursorOperators) { EXPECT_EQ(2, curs1 - curs2); EXPECT_THROW(curs2 - curs1, std::out_of_range); } + + // Test isAtEnd() with empty buffers at the end of a chain + { + auto iobuf1 = IOBuf::create(20); + iobuf1->append(15); + iobuf1->trimStart(5); + + Cursor c(iobuf1.get()); + EXPECT_FALSE(c.isAtEnd()); + c.skip(10); + EXPECT_TRUE(c.isAtEnd()); + + iobuf1->prependChain(IOBuf::create(10)); + iobuf1->prependChain(IOBuf::create(10)); + EXPECT_TRUE(c.isAtEnd()); + iobuf1->prev()->append(5); + EXPECT_FALSE(c.isAtEnd()); + c.skip(5); + EXPECT_TRUE(c.isAtEnd()); + } } TEST(IOBuf, StringOperations) {