Commit efca08ae authored by Adam Simpkins's avatar Adam Simpkins Committed by Andre Azevedo

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
parent 5924c69c
......@@ -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<Derived*>(this);
p->skip(offset);
......
......@@ -263,9 +263,11 @@ TEST(IOBuf, pushCursorData) {
//write 20 bytes to the buffer chain
RWPrivateCursor wcursor(iobuf1.get());
EXPECT_FALSE(wcursor.isAtEnd());
wcursor.writeBE<uint64_t>(1);
wcursor.writeBE<uint64_t>(10);
wcursor.writeBE<uint32_t>(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<const char*>(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) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment