diff --git a/folly/experimental/io/IOBuf.h b/folly/experimental/io/IOBuf.h
index e48650aca49a7d3769974df57cd4e98aa73bfd6c..3a0abb8a7815655d7ed1b4cee2f53fd28399a83a 100644
--- a/folly/experimental/io/IOBuf.h
+++ b/folly/experimental/io/IOBuf.h
@@ -299,6 +299,29 @@ class IOBuf {
uint32_t headroom=0,
uint32_t minTailroom=0);
+ /**
+ * Convenience function to create a new IOBuf object that copies data from a
+ * user-supplied string, optionally allocating a given amount of
+ * headroom and tailroom.
+ *
+ * Beware when attempting to invoke this function with a constant string
+ * literal and a headroom argument: you will likely end up invoking the
+ * version of copyBuffer() above. IOBuf::copyBuffer("hello", 3) will treat
+ * the first argument as a const void*, and will invoke the version of
+ * copyBuffer() above, with the size argument of 3.
+ */
+ static std::unique_ptr<IOBuf> copyBuffer(const std::string& buf,
+ uint32_t headroom=0,
+ uint32_t minTailroom=0);
+
+ /**
+ * A version of copyBuffer() that returns a null pointer if the input string
+ * is empty.
+ */
+ static std::unique_ptr<IOBuf> maybeCopyBuffer(const std::string& buf,
+ uint32_t headroom=0,
+ uint32_t minTailroom=0);
+
/**
* Convenience function to free a chain of IOBufs held by a unique_ptr.
*/
@@ -1076,6 +1099,21 @@ inline std::unique_ptr<IOBuf> IOBuf::copyBuffer(
return buf;
}
+inline std::unique_ptr<IOBuf> IOBuf::copyBuffer(const std::string& buf,
+ uint32_t headroom,
+ uint32_t minTailroom) {
+ return copyBuffer(buf.data(), buf.size(), headroom, minTailroom);
+}
+
+inline std::unique_ptr<IOBuf> IOBuf::maybeCopyBuffer(const std::string& buf,
+ uint32_t headroom,
+ uint32_t minTailroom) {
+ if (buf.empty()) {
+ return nullptr;
+ }
+ return copyBuffer(buf.data(), buf.size(), headroom, minTailroom);
+}
+
} // folly
#endif // FOLLY_IO_IOBUF_H_
diff --git a/folly/experimental/io/test/IOBufTest.cpp b/folly/experimental/io/test/IOBufTest.cpp
index b16511a4d90d3229b1dc20f3981f221549e53023..f6f6fe28dfeb6d7bc7a30217312ba2f5c5540b75 100644
--- a/folly/experimental/io/test/IOBufTest.cpp
+++ b/folly/experimental/io/test/IOBufTest.cpp
@@ -550,6 +550,34 @@ TEST(IOBuf, copyBuffer) {
EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(buf->data()),
buf->length()));
EXPECT_LE(2, buf->tailroom());
+
+ buf = IOBuf::copyBuffer(s, 5, 7);
+ EXPECT_EQ(5, buf->headroom());
+ EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(buf->data()),
+ buf->length()));
+ EXPECT_LE(7, buf->tailroom());
+
+ std::string empty;
+ buf = IOBuf::copyBuffer(empty, 3, 6);
+ EXPECT_EQ(3, buf->headroom());
+ EXPECT_EQ(0, buf->length());
+ EXPECT_LE(6, buf->tailroom());
+}
+
+TEST(IOBuf, maybeCopyBuffer) {
+ std::string s("this is a test");
+ auto buf = IOBuf::maybeCopyBuffer(s, 1, 2);
+ EXPECT_EQ(1, buf->headroom());
+ EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(buf->data()),
+ buf->length()));
+ EXPECT_LE(2, buf->tailroom());
+
+ std::string empty;
+ buf = IOBuf::maybeCopyBuffer("", 5, 7);
+ EXPECT_EQ(nullptr, buf.get());
+
+ buf = IOBuf::maybeCopyBuffer("");
+ EXPECT_EQ(nullptr, buf.get());
}
namespace {