return Iterator(nullptr, nullptr);
}
+folly::fbvector<struct iovec> IOBuf::getIov() const {
+ folly::fbvector<struct iovec> iov;
+ iov.reserve(countChainElements());
+ IOBuf const* p = this;
+ do {
+ // some code can get confused by empty iovs, so skip them
+ if (p->length() > 0) {
+ iov.push_back({(void*)p->data(), p->length()});
+ }
+ p = p->next();
+ } while (p != this);
+ return iov;
+}
+
} // folly
#include <cstring>
#include <memory>
#include <limits>
+#include <sys/uio.h>
#include <type_traits>
#include <boost/iterator/iterator_facade.hpp>
#include "folly/FBString.h"
#include "folly/Range.h"
+#include "folly/FBVector.h"
namespace folly {
*/
std::unique_ptr<IOBuf> cloneOne() const;
+ /**
+ * Return an iovector suitable for e.g. writev()
+ *
+ * auto iov = buf->getIov();
+ * auto xfer = writev(fd, iov.data(), iov.size());
+ *
+ * Naturally, the returned iovector is invalid if you modify the buffer
+ * chain.
+ */
+ folly::fbvector<struct iovec> getIov() const;
+
// Overridden operator new and delete.
// These directly use malloc() and free() to allocate the space for IOBuf
// objects. This is needed since IOBuf::create() manually uses malloc when
#include "folly/Range.h"
using folly::fbstring;
+using folly::fbvector;
using folly::IOBuf;
using folly::TypedIOBuf;
using folly::StringPiece;
::testing::Values(1, 2, 10), // element count
::testing::Bool())); // shared
+TEST(IOBuf, getIov) {
+ uint32_t fillSeed = 0xdeadbeef;
+ boost::mt19937 gen(fillSeed);
+
+ size_t len = 4096;
+ size_t count = 32;
+ auto buf = IOBuf::create(len + 1);
+ buf->append(rand() % len + 1);
+ fillBuf(buf.get(), gen);
+
+ for (size_t i = 0; i < count - 1; i++) {
+ auto buf2 = IOBuf::create(len + 1);
+ buf2->append(rand() % len + 1);
+ fillBuf(buf2.get(), gen);
+ buf->prependChain(std::move(buf2));
+ }
+ EXPECT_EQ(count, buf->countChainElements());
+
+ auto iov = buf->getIov();
+ EXPECT_EQ(count, iov.size());
+
+ IOBuf const* p = buf.get();
+ for (size_t i = 0; i < count; i++, p = p->next()) {
+ EXPECT_EQ(p->data(), iov[i].iov_base);
+ EXPECT_EQ(p->length(), iov[i].iov_len);
+ }
+
+ // an empty buf should be skipped in the iov.
+ buf->next()->clear();
+ iov = buf->getIov();
+ EXPECT_EQ(count - 1, iov.size());
+ EXPECT_EQ(buf->next()->next()->data(), iov[1].iov_base);
+
+ // same for the first one being empty
+ buf->clear();
+ iov = buf->getIov();
+ EXPECT_EQ(count - 2, iov.size());
+ EXPECT_EQ(buf->next()->next()->data(), iov[0].iov_base);
+
+ // and the last one
+ buf->prev()->clear();
+ iov = buf->getIov();
+ EXPECT_EQ(count - 3, iov.size());
+}
+
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
google::ParseCommandLineFlags(&argc, &argv, true);