Commit 6a6efad5 authored by Adam Simpkins's avatar Adam Simpkins Committed by Facebook Github Bot 0

add Cursor::peekBytes()

Summary:
The existing Cursor::peek() method pre-dates the existence of folly::ByteRange,
and so it returns a std::pair containing a pointer and length.  This is usually
more awkward to use than ByteRange.

This adds a peekBytes() method that returns a ByteRange object, and updates all
users of peek() in folly to use peekBytes() instead.  Eventually I think we
should add a FOLLY_DEPRECATED attribute to peek().  I will wait to add this tag
until after converting a few other projects to use peekBytes(), though.

Reviewed By: alandau

Differential Revision: D3337302

fbshipit-source-id: 14220a059d915bf5adc66b8b283f7228b796a4dc
parent 1f4f1754
...@@ -606,21 +606,23 @@ pid_t Subprocess::pid() const { ...@@ -606,21 +606,23 @@ pid_t Subprocess::pid() const {
namespace { namespace {
std::pair<const uint8_t*, size_t> queueFront(const IOBufQueue& queue) { ByteRange queueFront(const IOBufQueue& queue) {
auto* p = queue.front(); auto* p = queue.front();
if (!p) return std::make_pair(nullptr, 0); if (!p) {
return io::Cursor(p).peek(); return ByteRange{};
}
return io::Cursor(p).peekBytes();
} }
// fd write // fd write
bool handleWrite(int fd, IOBufQueue& queue) { bool handleWrite(int fd, IOBufQueue& queue) {
for (;;) { for (;;) {
auto p = queueFront(queue); auto b = queueFront(queue);
if (p.second == 0) { if (b.empty()) {
return true; // EOF return true; // EOF
} }
ssize_t n = writeNoInt(fd, p.first, p.second); ssize_t n = writeNoInt(fd, b.data(), b.size());
if (n == -1 && errno == EAGAIN) { if (n == -1 && errno == EAGAIN) {
return false; return false;
} }
......
...@@ -116,8 +116,8 @@ static dynamic decodeTemplate(Cursor& curs) { ...@@ -116,8 +116,8 @@ static dynamic decodeTemplate(Cursor& curs) {
dynamic obj = dynamic::object; dynamic obj = dynamic::object;
for (auto& name : names) { for (auto& name : names) {
auto pair = curs.peek(); auto bytes = curs.peekBytes();
if ((BserType)pair.first[0] == BserType::Skip) { if ((BserType)bytes.at(0) == BserType::Skip) {
obj[name.getString()] = nullptr; obj[name.getString()] = nullptr;
curs.skipAtMost(1); curs.skipAtMost(1);
continue; continue;
...@@ -176,7 +176,7 @@ static size_t decodeHeader(Cursor& curs) { ...@@ -176,7 +176,7 @@ static size_t decodeHeader(Cursor& curs) {
throw std::runtime_error("invalid BSER magic header"); throw std::runtime_error("invalid BSER magic header");
} }
auto enc = (BserType)curs.peek().first[0]; auto enc = (BserType)curs.peekBytes().at(0);
size_t int_size; size_t int_size;
switch (enc) { switch (enc) {
case BserType::Int8: case BserType::Int8:
......
...@@ -303,12 +303,13 @@ std::unique_ptr<IOBuf> LZ4Codec::doUncompress( ...@@ -303,12 +303,13 @@ std::unique_ptr<IOBuf> LZ4Codec::doUncompress(
} }
} }
auto p = cursor.peek(); auto sp = StringPiece{cursor.peekBytes()};
auto out = IOBuf::create(actualUncompressedLength); auto out = IOBuf::create(actualUncompressedLength);
int n = LZ4_decompress_safe(reinterpret_cast<const char*>(p.first), int n = LZ4_decompress_safe(
reinterpret_cast<char*>(out->writableTail()), sp.data(),
p.second, reinterpret_cast<char*>(out->writableTail()),
actualUncompressedLength); sp.size(),
actualUncompressedLength);
if (n < 0 || uint64_t(n) != actualUncompressedLength) { if (n < 0 || uint64_t(n) != actualUncompressedLength) {
throw std::runtime_error(to<std::string>( throw std::runtime_error(to<std::string>(
...@@ -350,9 +351,9 @@ size_t IOBufSnappySource::Available() const { ...@@ -350,9 +351,9 @@ size_t IOBufSnappySource::Available() const {
} }
const char* IOBufSnappySource::Peek(size_t* len) { const char* IOBufSnappySource::Peek(size_t* len) {
auto p = cursor_.peek(); auto sp = StringPiece{cursor_.peekBytes()};
*len = p.second; *len = sp.size();
return reinterpret_cast<const char*>(p.first); return sp.data();
} }
void IOBufSnappySource::Skip(size_t n) { void IOBufSnappySource::Skip(size_t n) {
...@@ -908,10 +909,10 @@ std::unique_ptr<IOBuf> LZMA2Codec::doUncompress(const IOBuf* data, ...@@ -908,10 +909,10 @@ std::unique_ptr<IOBuf> LZMA2Codec::doUncompress(const IOBuf* data,
defaultBufferLength)); defaultBufferLength));
bool streamEnd = false; bool streamEnd = false;
auto buf = cursor.peek(); auto buf = cursor.peekBytes();
while (buf.second != 0) { while (!buf.empty()) {
stream.next_in = const_cast<uint8_t*>(buf.first); stream.next_in = const_cast<uint8_t*>(buf.data());
stream.avail_in = buf.second; stream.avail_in = buf.size();
while (stream.avail_in != 0) { while (stream.avail_in != 0) {
if (streamEnd) { if (streamEnd) {
...@@ -922,8 +923,8 @@ std::unique_ptr<IOBuf> LZMA2Codec::doUncompress(const IOBuf* data, ...@@ -922,8 +923,8 @@ std::unique_ptr<IOBuf> LZMA2Codec::doUncompress(const IOBuf* data,
streamEnd = doInflate(&stream, out.get(), defaultBufferLength); streamEnd = doInflate(&stream, out.get(), defaultBufferLength);
} }
cursor.skip(buf.second); cursor.skip(buf.size());
buf = cursor.peek(); buf = cursor.peekBytes();
} }
while (!streamEnd) { while (!streamEnd) {
......
...@@ -86,10 +86,10 @@ class CursorBase { ...@@ -86,10 +86,10 @@ class CursorBase {
/** /**
* Return the remaining space available in the current IOBuf. * Return the remaining space available in the current IOBuf.
* *
* May return 0 if the cursor is at the end of an IOBuf. Use peek() instead * May return 0 if the cursor is at the end of an IOBuf. Use peekBytes()
* if you want to avoid this. peek() will advance to the next non-empty * instead if you want to avoid this. peekBytes() will advance to the next
* IOBuf (up to the end of the chain) if the cursor is currently pointing at * non-empty IOBuf (up to the end of the chain) if the cursor is currently
* the end of a buffer. * pointing at the end of a buffer.
*/ */
size_t length() const { size_t length() const {
return crtBuf_->length() - offset_; return crtBuf_->length() - offset_;
...@@ -300,15 +300,26 @@ class CursorBase { ...@@ -300,15 +300,26 @@ class CursorBase {
/** /**
* Return the available data in the current buffer. * Return the available data in the current buffer.
* If you want to gather more data from the chain into a contiguous region * If you want to gather more data from the chain into a contiguous region
* (for hopefully zero-copy access), use gather() before peek(). * (for hopefully zero-copy access), use gather() before peekBytes().
*/ */
std::pair<const uint8_t*, size_t> peek() { ByteRange peekBytes() {
// Ensure that we're pointing to valid data // Ensure that we're pointing to valid data
size_t available = length(); size_t available = length();
while (UNLIKELY(available == 0 && tryAdvanceBuffer())) { while (UNLIKELY(available == 0 && tryAdvanceBuffer())) {
available = length(); available = length();
} }
return std::make_pair(data(), available); return ByteRange{data(), available};
}
/**
* Alternate version of peekBytes() that returns a std::pair
* instead of a ByteRange. (This method pre-dates ByteRange.)
*
* This function will eventually be deprecated.
*/
std::pair<const uint8_t*, size_t> peek() {
auto bytes = peekBytes();
return std::make_pair(bytes.data(), bytes.size());
} }
void clone(std::unique_ptr<folly::IOBuf>& buf, size_t len) { void clone(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
...@@ -583,9 +594,9 @@ class Writable { ...@@ -583,9 +594,9 @@ class Writable {
size_t pushAtMost(Cursor cursor, size_t len) { size_t pushAtMost(Cursor cursor, size_t len) {
size_t written = 0; size_t written = 0;
for(;;) { for(;;) {
auto currentBuffer = cursor.peek(); auto currentBuffer = cursor.peekBytes();
const uint8_t* crtData = currentBuffer.first; const uint8_t* crtData = currentBuffer.data();
size_t available = currentBuffer.second; size_t available = currentBuffer.size();
if (available == 0) { if (available == 0) {
// end of buffer chain // end of buffer chain
return written; return written;
......
...@@ -962,12 +962,12 @@ size_t IOBufHash::operator()(const IOBuf& buf) const { ...@@ -962,12 +962,12 @@ size_t IOBufHash::operator()(const IOBuf& buf) const {
hasher.Init(0, 0); hasher.Init(0, 0);
io::Cursor cursor(&buf); io::Cursor cursor(&buf);
for (;;) { for (;;) {
auto p = cursor.peek(); auto b = cursor.peekBytes();
if (p.second == 0) { if (b.empty()) {
break; break;
} }
hasher.Update(p.first, p.second); hasher.Update(b.data(), b.size());
cursor.skip(p.second); cursor.skip(b.size());
} }
uint64_t h1; uint64_t h1;
uint64_t h2; uint64_t h2;
...@@ -979,16 +979,16 @@ bool IOBufEqual::operator()(const IOBuf& a, const IOBuf& b) const { ...@@ -979,16 +979,16 @@ bool IOBufEqual::operator()(const IOBuf& a, const IOBuf& b) const {
io::Cursor ca(&a); io::Cursor ca(&a);
io::Cursor cb(&b); io::Cursor cb(&b);
for (;;) { for (;;) {
auto pa = ca.peek(); auto ba = ca.peekBytes();
auto pb = cb.peek(); auto bb = cb.peekBytes();
if (pa.second == 0 && pb.second == 0) { if (ba.empty() && bb.empty()) {
return true; return true;
} else if (pa.second == 0 || pb.second == 0) { } else if (ba.empty() || bb.empty()) {
return false; return false;
} }
size_t n = std::min(pa.second, pb.second); size_t n = std::min(ba.size(), bb.size());
DCHECK_GT(n, 0); DCHECK_GT(n, 0);
if (memcmp(pa.first, pb.first, n)) { if (memcmp(ba.data(), bb.data(), n)) {
return false; return false;
} }
ca.skip(n); ca.skip(n);
......
...@@ -70,7 +70,7 @@ BENCHMARK(skipBenchmark, iters) { ...@@ -70,7 +70,7 @@ BENCHMARK(skipBenchmark, iters) {
while (iters--) { while (iters--) {
Cursor c(iobuf_read_benchmark.get()); Cursor c(iobuf_read_benchmark.get());
for (int i = 0; i < benchmark_size; i++) { for (int i = 0; i < benchmark_size; i++) {
c.peek(); c.peekBytes();
c.skip(1); c.skip(1);
} }
} }
......
...@@ -182,10 +182,10 @@ void append(Appender& appender, StringPiece data) { ...@@ -182,10 +182,10 @@ void append(Appender& appender, StringPiece data) {
std::string toString(const IOBuf& buf) { std::string toString(const IOBuf& buf) {
std::string str; std::string str;
Cursor cursor(&buf); Cursor cursor(&buf);
std::pair<const uint8_t*, size_t> p; ByteRange b;
while ((p = cursor.peek()).second) { while (!(b = cursor.peekBytes()).empty()) {
str.append(reinterpret_cast<const char*>(p.first), p.second); str.append(reinterpret_cast<const char*>(b.data()), b.size());
cursor.skip(p.second); cursor.skip(b.size());
} }
return str; return str;
} }
...@@ -218,18 +218,15 @@ TEST(IOBuf, PullAndPeek) { ...@@ -218,18 +218,15 @@ TEST(IOBuf, PullAndPeek) {
{ {
RWPrivateCursor cursor(iobuf1.get()); RWPrivateCursor cursor(iobuf1.get());
auto p = cursor.peek(); auto b = cursor.peekBytes();
EXPECT_EQ("he", std::string(reinterpret_cast<const char*>(p.first), EXPECT_EQ("he", StringPiece(b));
p.second)); cursor.skip(b.size());
cursor.skip(p.second); b = cursor.peekBytes();
p = cursor.peek(); EXPECT_EQ("llo ", StringPiece(b));
EXPECT_EQ("llo ", std::string(reinterpret_cast<const char*>(p.first), cursor.skip(b.size());
p.second)); b = cursor.peekBytes();
cursor.skip(p.second); EXPECT_EQ("world", StringPiece(b));
p = cursor.peek(); cursor.skip(b.size());
EXPECT_EQ("world", std::string(reinterpret_cast<const char*>(p.first),
p.second));
cursor.skip(p.second);
EXPECT_EQ(3, iobuf1->countChainElements()); EXPECT_EQ(3, iobuf1->countChainElements());
EXPECT_EQ(11, iobuf1->computeChainDataLength()); EXPECT_EQ(11, iobuf1->computeChainDataLength());
} }
...@@ -237,9 +234,8 @@ TEST(IOBuf, PullAndPeek) { ...@@ -237,9 +234,8 @@ TEST(IOBuf, PullAndPeek) {
{ {
RWPrivateCursor cursor(iobuf1.get()); RWPrivateCursor cursor(iobuf1.get());
cursor.gather(11); cursor.gather(11);
auto p = cursor.peek(); auto b = cursor.peekBytes();
EXPECT_EQ("hello world", std::string(reinterpret_cast<const EXPECT_EQ("hello world", StringPiece(b));
char*>(p.first), p.second));
EXPECT_EQ(1, iobuf1->countChainElements()); EXPECT_EQ(1, iobuf1->countChainElements());
EXPECT_EQ(11, iobuf1->computeChainDataLength()); EXPECT_EQ(11, iobuf1->computeChainDataLength());
} }
...@@ -377,7 +373,7 @@ TEST(IOBuf, cloneAndInsert) { ...@@ -377,7 +373,7 @@ TEST(IOBuf, cloneAndInsert) {
EXPECT_EQ(7, iobuf1->countChainElements()); EXPECT_EQ(7, iobuf1->countChainElements());
EXPECT_EQ(14, iobuf1->computeChainDataLength()); EXPECT_EQ(14, iobuf1->computeChainDataLength());
// Check that nextBuf got set correctly to the buffer with 1 byte left // Check that nextBuf got set correctly to the buffer with 1 byte left
EXPECT_EQ(1, cursor.peek().second); EXPECT_EQ(1, cursor.peekBytes().size());
cursor.read<uint8_t>(); cursor.read<uint8_t>();
} }
......
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