+}
+
+size_t IOBuf::fillIov(struct iovec* iov, size_t len) const {
+ IOBuf const* p = this;
+ size_t i = 0;
+ while (i < len) {
+ // some code can get confused by empty iovs, so skip them
+ if (p->length() > 0) {
+ iov[i].iov_base = const_cast<uint8_t*>(p->data());
+ iov[i].iov_len = p->length();
+ i++;
+ }
+ p = p->next();
+ if (p == this) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+size_t IOBufHash::operator()(const IOBuf& buf) const {
+ folly::hash::SpookyHashV2 hasher;
+ hasher.Init(0, 0);
+ io::Cursor cursor(&buf);
+ for (;;) {
+ auto p = cursor.peek();
+ if (p.second == 0) {
+ break;
+ }
+ hasher.Update(p.first, p.second);
+ cursor.skip(p.second);
+ }
+ uint64_t h1;
+ uint64_t h2;
+ hasher.Final(&h1, &h2);
+ return h1;
+}
+
+bool IOBufEqual::operator()(const IOBuf& a, const IOBuf& b) const {
+ io::Cursor ca(&a);
+ io::Cursor cb(&b);
+ for (;;) {
+ auto pa = ca.peek();
+ auto pb = cb.peek();
+ if (pa.second == 0 && pb.second == 0) {
+ return true;
+ } else if (pa.second == 0 || pb.second == 0) {
+ return false;
+ }
+ size_t n = std::min(pa.second, pb.second);
+ DCHECK_GT(n, 0);
+ if (memcmp(pa.first, pb.first, n)) {
+ return false;
+ }
+ ca.skip(n);
+ cb.skip(n);
+ }