X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Fio%2FCursor.h;h=c16c6a45692bf41736ecb6a6b731b1032e3f6450;hb=6f8d37dc510dfbbf8beacc67b23d937bff69182d;hp=5e1ce527b5c0ed28548471280460df7a719af436;hpb=6a6efad5faf702f61820268cca8726a83bc6a9d2;p=folly.git diff --git a/folly/io/Cursor.h b/folly/io/Cursor.h index 5e1ce527..c16c6a45 100644 --- a/folly/io/Cursor.h +++ b/folly/io/Cursor.h @@ -1,5 +1,5 @@ /* - * Copyright 2016 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,12 +24,13 @@ #include #include -#include -#include #include #include #include #include +#include +#include +#include /** * Cursor class for fast iteration over IOBuf chains. @@ -152,6 +153,17 @@ class CursorBase { return true; } + /** + * Advances the cursor to the end of the entire IOBuf chain. + */ + void advanceToEnd() { + offset_ = buffer_->prev()->length(); + if (crtBuf_ != buffer_->prev()) { + crtBuf_ = buffer_->prev(); + static_cast(this)->advanceDone(); + } + } + Derived& operator+=(size_t offset) { Derived* p = static_cast(this); p->skip(offset); @@ -163,6 +175,17 @@ class CursorBase { return other; } + Derived& operator-=(size_t offset) { + Derived* p = static_cast(this); + p->retreat(offset); + return *p; + } + Derived operator-(size_t offset) const { + Derived other(*this); + other.retreat(offset); + return other; + } + /** * Compare cursors for equality/inequality. * @@ -229,34 +252,36 @@ class CursorBase { */ std::string readTerminatedString( char termChar = '\0', - size_t maxLength = std::numeric_limits::max()) { - std::string str; - - while (!isAtEnd()) { - const uint8_t* buf = data(); - size_t buflen = length(); - - size_t i = 0; - while (i < buflen && buf[i] != termChar) { - ++i; + size_t maxLength = std::numeric_limits::max()); - // Do this check after incrementing 'i', as even though we start at the - // 0 byte, it still represents a single character - if (str.length() + i >= maxLength) { - throw std::length_error("string overflow"); - } - } + /* + * Read all bytes until the specified predicate returns true. + * + * The predicate will be called on each byte in turn, until it returns false + * or until the end of the IOBuf chain is reached. + * + * Returns the result as a string. + */ + template + std::string readWhile(const Predicate& predicate); - str.append(reinterpret_cast(buf), i); - if (i < buflen) { - skip(i + 1); - return str; - } + /* + * Read all bytes until the specified predicate returns true. + * + * This is a more generic version of readWhile() takes an arbitrary Output + * object, and calls Output::append() with each chunk of matching data. + */ + template + void readWhile(const Predicate& predicate, Output& out); - skip(i); - } - throw std::out_of_range("terminator not found"); - } + /* + * Skip all bytes until the specified predicate returns true. + * + * The predicate will be called on each byte in turn, until it returns false + * or until the end of the IOBuf chain is reached. + */ + template + void skipWhile(const Predicate& predicate); size_t skipAtMost(size_t len) { if (LIKELY(length() >= len)) { @@ -276,6 +301,22 @@ class CursorBase { } } + size_t retreatAtMost(size_t len) { + if (len <= offset_) { + offset_ -= len; + return len; + } + return retreatAtMostSlow(len); + } + + void retreat(size_t len) { + if (len <= offset_) { + offset_ -= len; + } else { + retreatSlow(len); + } + } + size_t pullAtMost(void* buf, size_t len) { // Fast path: it all fits in one buffer. if (LIKELY(length() >= len)) { @@ -324,13 +365,13 @@ class CursorBase { void clone(std::unique_ptr& buf, size_t len) { if (UNLIKELY(cloneAtMost(buf, len) != len)) { - throw std::out_of_range("underflow"); + std::__throw_out_of_range("underflow"); } } void clone(folly::IOBuf& buf, size_t len) { if (UNLIKELY(cloneAtMost(buf, len) != len)) { - throw std::out_of_range("underflow"); + std::__throw_out_of_range("underflow"); } } @@ -398,13 +439,13 @@ class CursorBase { } if (otherBuf == other.buffer_) { - throw std::out_of_range("wrap-around"); + std::__throw_out_of_range("wrap-around"); } len += offset_; } else { if (offset_ < other.offset_) { - throw std::out_of_range("underflow"); + std::__throw_out_of_range("underflow"); } len += offset_ - other.offset_; @@ -419,12 +460,12 @@ class CursorBase { size_t operator-(const BufType* buf) const { size_t len = 0; - BufType *curBuf = buf; + const BufType* curBuf = buf; while (curBuf != crtBuf_) { len += curBuf->length(); curBuf = curBuf->next(); if (curBuf == buf || curBuf == buffer_) { - throw std::out_of_range("wrap-around"); + std::__throw_out_of_range("wrap-around"); } } @@ -452,6 +493,17 @@ class CursorBase { return true; } + bool tryRetreatBuffer() { + if (UNLIKELY(crtBuf_ == buffer_)) { + offset_ = 0; + return false; + } + crtBuf_ = crtBuf_->prev(); + offset_ = crtBuf_->length(); + static_cast(this)->advanceDone(); + return true; + } + void advanceBufferIfEmpty() { if (length() == 0) { tryAdvanceBuffer(); @@ -466,7 +518,7 @@ class CursorBase { for (size_t available; (available = length()) < len; ) { str->append(reinterpret_cast(data()), available); if (UNLIKELY(!tryAdvanceBuffer())) { - throw std::out_of_range("string underflow"); + std::__throw_out_of_range("string underflow"); } len -= available; } @@ -495,7 +547,7 @@ class CursorBase { void pullSlow(void* buf, size_t len) { if (UNLIKELY(pullAtMostSlow(buf, len) != len)) { - throw std::out_of_range("underflow"); + std::__throw_out_of_range("underflow"); } } @@ -515,7 +567,26 @@ class CursorBase { void skipSlow(size_t len) { if (UNLIKELY(skipAtMostSlow(len) != len)) { - throw std::out_of_range("underflow"); + std::__throw_out_of_range("underflow"); + } + } + + size_t retreatAtMostSlow(size_t len) { + size_t retreated = 0; + for (size_t available; (available = offset_) < len;) { + retreated += available; + if (UNLIKELY(!tryRetreatBuffer())) { + return retreated; + } + len -= available; + } + offset_ -= len; + return retreated + len; + } + + void retreatSlow(size_t len) { + if (UNLIKELY(retreatAtMostSlow(len) != len)) { + std::__throw_out_of_range("underflow"); } } @@ -565,13 +636,13 @@ class Writable { void push(const uint8_t* buf, size_t len) { Derived* d = static_cast(this); if (d->pushAtMost(buf, len) != len) { - throw std::out_of_range("overflow"); + std::__throw_out_of_range("overflow"); } } void push(ByteRange buf) { if (this->pushAtMost(buf) != buf.size()) { - throw std::out_of_range("overflow"); + std::__throw_out_of_range("overflow"); } } @@ -587,7 +658,7 @@ class Writable { */ void push(Cursor cursor, size_t len) { if (this->pushAtMost(cursor, len) != len) { - throw std::out_of_range("overflow"); + std::__throw_out_of_range("overflow"); } } @@ -781,7 +852,7 @@ class Appender : public detail::Writable { // Waste the rest of the current buffer and allocate a new one. // Don't make it too small, either. if (growth_ == 0) { - throw std::out_of_range("can't grow buffer chain"); + std::__throw_out_of_range("can't grow buffer chain"); } n = std::max(n, growth_); @@ -934,3 +1005,5 @@ class QueueAppender : public detail::Writable { }; }} // folly::io + +#include