+ /**
+ * Return true if the cursor could advance the specified number of bytes
+ * from its current position.
+ * This is useful for applications that want to do checked reads instead of
+ * catching exceptions and is more efficient than using totalLength as it
+ * walks the minimal set of buffers in the chain to determine the result.
+ */
+ bool canAdvance(size_t amount) const {
+ const IOBuf* nextBuf = crtBuf_;
+ size_t available = length();
+ do {
+ if (available >= amount) {
+ return true;
+ }
+ amount -= available;
+ nextBuf = nextBuf->next();
+ available = nextBuf->length();
+ } while (nextBuf != buffer_);
+ return false;
+ }
+
+ /*
+ * 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;
+ }
+
+ /**
+ * 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<Derived*>(this)->advanceDone();
+ }
+ }
+