From: Peter Griess Date: Mon, 28 Jan 2013 18:05:16 +0000 (-0800) Subject: Add some CursorBase::operator-() implementations X-Git-Tag: v0.22.0~1068 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=9547cef8ad056d7eb661968ca374165f7d6e353b;p=folly.git Add some CursorBase::operator-() implementations 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 --- diff --git a/folly/io/Cursor.h b/folly/io/Cursor.h index 811c2e6a..73a5493a 100644 --- a/folly/io/Cursor.h +++ b/folly/io/Cursor.h @@ -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_; diff --git a/folly/io/test/IOBufCursorTest.cpp b/folly/io/test/IOBufCursorTest.cpp index c1fe8967..3ce32ad6 100644 --- a/folly/io/test/IOBufCursorTest.cpp +++ b/folly/io/test/IOBufCursorTest.cpp @@ -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 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 chain1(IOBuf::create(20)); + chain1->append(10); + std::unique_ptr 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 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_benchmark;