Skip to content

Commit

Permalink
Add some CursorBase::operator-() implementations
Browse files Browse the repository at this point in the history
Summary:
- Add CursorBase::operator-() implementations for Cursor and BufType;
useful for figuring out the distance between two objects

Test Plan: - Used in some other code

Reviewed By: simpkins@fb.com

FB internal diff: D690046
  • Loading branch information
Peter Griess authored and jdelong committed Mar 19, 2013
1 parent 2a80dba commit 9547cef
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 0 deletions.
51 changes: 51 additions & 0 deletions folly/io/Cursor.h
Expand Up @@ -216,6 +216,57 @@ class CursorBase {
}
}

/**
* Return the distance between two cursors.
*/
size_t operator-(const CursorBase& other) const {
BufType *otherBuf = other.crtBuf_;
size_t len = 0;

if (otherBuf != crtBuf_) {
len += otherBuf->length() - other.offset_;

for (otherBuf = otherBuf->next();
otherBuf != crtBuf_ && otherBuf != other.buffer_;
otherBuf = otherBuf->next()) {
len += otherBuf->length();
}

if (otherBuf == other.buffer_) {
throw std::out_of_range("wrap-around");
}

len += offset_;
} else {
if (offset_ < other.offset_) {
throw std::out_of_range("underflow");
}

len += offset_ - other.offset_;
}

return len;
}

/**
* Return the distance from the given IOBuf to the this cursor.
*/
size_t operator-(const BufType* buf) const {
size_t len = 0;

BufType *curBuf = buf;
while (curBuf != crtBuf_) {
len += curBuf->length();
curBuf = curBuf->next();
if (curBuf == buf || curBuf == buffer_) {
throw std::out_of_range("wrap-around");
}
}

len += offset_;
return len;
}

protected:
BufType* crtBuf_;
size_t offset_;
Expand Down
57 changes: 57 additions & 0 deletions folly/io/test/IOBufCursorTest.cpp
Expand Up @@ -326,6 +326,63 @@ TEST(IOBuf, Appender) {
EXPECT_EQ("hello world", toString(*head));
}

TEST(IOBuf, CursorOperators) {
// Test operators on a single-item chain
{
std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
chain1->append(10);

Cursor curs1(chain1.get());
EXPECT_EQ(0, curs1 - chain1.get());
curs1.skip(3);
EXPECT_EQ(3, curs1 - chain1.get());
curs1.skip(7);
EXPECT_EQ(10, curs1 - chain1.get());

Cursor curs2(chain1.get());
EXPECT_EQ(0, curs2 - chain1.get());
EXPECT_EQ(10, curs1 - curs2);
EXPECT_THROW(curs2 - curs1, std::out_of_range);
}

// Test cross-chain operations
{
std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
chain1->append(10);
std::unique_ptr<IOBuf> chain2 = chain1->clone();

Cursor curs1(chain1.get());
Cursor curs2(chain2.get());
EXPECT_THROW(curs1 - curs2, std::out_of_range);
EXPECT_THROW(curs1 - chain2.get(), std::out_of_range);
}

// Test operations on multi-item chains
{
std::unique_ptr<IOBuf> chain(IOBuf::create(20));
chain->append(10);
chain->appendChain(chain->clone());
EXPECT_EQ(20, chain->computeChainDataLength());

Cursor curs1(chain.get());
curs1.skip(5);
Cursor curs2(chain.get());
curs2.skip(3);
EXPECT_EQ(2, curs1 - curs2);
EXPECT_EQ(5, curs1 - chain.get());
EXPECT_THROW(curs2 - curs1, std::out_of_range);

curs1.skip(7);
EXPECT_EQ(9, curs1 - curs2);
EXPECT_EQ(12, curs1 - chain.get());
EXPECT_THROW(curs2 - curs1, std::out_of_range);

curs2.skip(7);
EXPECT_EQ(2, curs1 - curs2);
EXPECT_THROW(curs2 - curs1, std::out_of_range);
}
}

int benchmark_size = 1000;
unique_ptr<IOBuf> iobuf_benchmark;

Expand Down

0 comments on commit 9547cef

Please sign in to comment.