+ return crtEnd_ - crtPos_;
+ }
+
+ /**
+ * Return the space available until the end of the entire IOBuf chain.
+ */
+ size_t totalLength() const {
+ if (crtBuf_ == buffer_) {
+ return crtBuf_->computeChainDataLength() - (crtPos_ - crtBegin_);
+ }
+ CursorBase end(buffer_->prev());
+ end.crtPos_ = end.crtEnd_;
+ return end - *this;
+ }
+
+ /**
+ * 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 (crtPos_ != crtEnd_) {
+ 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() {
+ // Simple case, we're already in the last IOBuf.
+ if (crtBuf_ == buffer_->prev()) {
+ crtPos_ = crtEnd_;
+ return;
+ }
+
+ auto* nextBuf = crtBuf_->next();
+ while (nextBuf != buffer_) {
+ absolutePos_ += crtEnd_ - crtBegin_;
+
+ crtBuf_ = nextBuf;
+ nextBuf = crtBuf_->next();
+ crtBegin_ = crtBuf_->data();
+ crtPos_ = crtEnd_ = crtBuf_->tail();
+
+ static_cast<Derived*>(this)->advanceDone();
+ }