Commit a79234f0 authored by Giuseppe Ottaviano's avatar Giuseppe Ottaviano Committed by Facebook GitHub Bot

Add IOBuf convenience methods to convert to std::string

Summary:
Getting an `std::string` out of the data in a `IOBuf` chain is a common operation in tests, logging, and at interface boundaries. Currently there isn't an easy way to do it, so either the same boilerplate is replicated everywhere, or people resort to `coalesce().str()`, which is inefficient (it can end up copying the data twice) and non-`const`.

Add methods to append and convert to any char container, like `string`, `fbstring`, `vector<char>`, ...

Reviewed By: philippv

Differential Revision: D31385345

fbshipit-source-id: 8a331771786f7bf1043b59d5c36ac4051e442531
parent 45082113
......@@ -168,12 +168,7 @@ bool Codec::canUncompress(
std::string Codec::doCompressString(const StringPiece data) {
const IOBuf inputBuffer{IOBuf::WRAP_BUFFER, data};
auto outputBuffer = doCompress(&inputBuffer);
std::string output;
output.reserve(outputBuffer->computeChainDataLength());
for (auto range : *outputBuffer) {
output.append(reinterpret_cast<const char*>(range.data()), range.size());
}
return output;
return outputBuffer->to<std::string>();
}
std::string Codec::doUncompressString(
......
......@@ -40,6 +40,8 @@ DEFINE_double(load_factor, 0.95, "Load factor of the multiset");
#if FOLLY_QUOTIENT_MULTI_SET_SUPPORTED
using std::string;
namespace {
static const unsigned int kRunsPerIteration = 5000000;
......@@ -48,7 +50,7 @@ std::mt19937 rng;
// Uniformly distributed keys.
std::vector<uint64_t> uniform;
std::string qmsData;
string qmsData;
uint64_t maxValue(uint32_t nbits) {
return nbits == 64 ? std::numeric_limits<uint64_t>::max()
......@@ -74,7 +76,7 @@ void buildQuotientMultiSet(std::vector<uint64_t>& keys) {
}
}
builder.close(buff);
qmsData = buff.move()->coalesce().toString();
qmsData = buff.move()->to<string>();
}
std::vector<uint64_t> makeLookupKeys(size_t n, double hitRate) {
......
......@@ -25,6 +25,7 @@
#include <cstdlib>
#include <limits>
#include <stdexcept>
#include <type_traits>
#include <folly/Conv.h>
#include <folly/Likely.h>
......
......@@ -148,10 +148,12 @@ namespace folly {
* Synchronization
* ---------------
*
* When used in multithread programs, a single IOBuf object should only be used
* in a single thread at a time. If a caller uses a single IOBuf across
* multiple threads the caller is responsible for using an external lock to
* synchronize access to the IOBuf.
* When used in multithread programs, a single IOBuf object should only be
* accessed mutably by a single thread at a time. All const member functions of
* IOBuf are safe to call concurrently with one another, but when a caller uses
* a single IOBuf across multiple threads and at least one thread calls a
* non-const member function, the caller is responsible for using an external
* lock to synchronize access to the IOBuf.
*
* Two separate IOBuf objects may be accessed concurrently in separate threads
* without locking, even if they point to the same underlying buffer. The
......@@ -163,9 +165,10 @@ namespace folly {
* another thread.
*
* For IOBuf chains, no two IOBufs in the same chain should be accessed
* simultaneously in separate threads. The caller must maintain a lock around
* the entire chain if the chain, or individual IOBufs in the chain, may be
* accessed by multiple threads.
* simultaneously in separate threads, except where all simultaneous accesses
* are to const member functions. The caller must maintain a lock around the
* entire chain if the chain, or individual IOBufs in the chain, may be accessed
* by multiple threads with at least one of the threads needing to mutate.
*
*
* IOBuf Object Allocation
......@@ -1328,6 +1331,21 @@ class IOBuf {
*/
void cloneOneInto(IOBuf& other) const { other = cloneOneAsValue(); }
/**
* Append the chain data into the provided container. This is meant to be used
* with containers such as std::string or std::vector<char>, but any container
* which supports reserve(), insert(), and has char or unsigned char value
* type is supported.
*/
template <class Container>
void appendTo(Container& container) const;
/**
* Convenience version of appendTo().
*/
template <class Container>
Container to() const;
/**
* Return an iovector suitable for e.g. writev()
*
......@@ -1832,6 +1850,25 @@ inline IOBuf::Iterator IOBuf::end() const {
return cend();
}
template <class Container>
void IOBuf::appendTo(Container& container) const {
static_assert(
(std::is_same<typename Container::value_type, char>::value ||
std::is_same<typename Container::value_type, unsigned char>::value),
"Unsupported value type");
container.reserve(container.size() + computeChainDataLength());
for (auto data : *this) {
container.insert(container.end(), data.begin(), data.end());
}
}
template <class Container>
Container IOBuf::to() const {
Container result;
appendTo(result);
return result;
}
} // namespace folly
FOLLY_POP_WARNING
......@@ -1779,3 +1779,32 @@ TEST(IOBuf, computeChainCapacityOfMixedCapacityChainedIOBuf) {
EXPECT_EQ(buf->computeChainCapacity(), 100);
}
TEST(IOBuf, AppendTo) {
using folly::range;
IOBuf buf;
EXPECT_EQ(buf.to<std::string>(), "");
auto temp = &buf;
temp->appendChain(IOBuf::copyBuffer("Hello"));
temp = temp->next();
temp->appendChain(IOBuf::copyBuffer(" and"));
temp = temp->next();
temp->appendChain(IOBuf::copyBuffer(" goodbye."));
auto testAppendTo = [&](auto c) {
const StringPiece kExpected = "Hello and goodbye.";
EXPECT_EQ(StringPiece(range(buf.to<decltype(c)>())), kExpected);
const StringPiece kPreviousData = "I was there before. ";
c.insert(c.end(), kPreviousData.begin(), kPreviousData.end());
buf.appendTo(c);
EXPECT_EQ(StringPiece(range(c)), kPreviousData.str() + kExpected.str());
};
testAppendTo(std::string{});
testAppendTo(fbstring{});
testAppendTo(std::vector<char>{});
testAppendTo(std::vector<unsigned char>{});
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment