Skip to content

Instantly share code, notes, and snippets.

@na-ka-na
Created November 10, 2016 20:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save na-ka-na/07db1eed4f8ba2bda5832c87c9338267 to your computer and use it in GitHub Desktop.
Save na-ka-na/07db1eed4f8ba2bda5832c87c9338267 to your computer and use it in GitHub Desktop.
// A ZeroCopyOutputStream which appends bytes to a string.
// It has much a more favorable performance profile than StringOutputStream
// outside of Google since STLStringResizeUninitialized() is un-optimized.
class LIBPROTOBUF_EXPORT StringOutputStream2 : public ZeroCopyOutputStream {
public:
explicit StringOutputStream2();
~StringOutputStream2();
// implements ZeroCopyOutputStream ---------------------------------
bool Next(void** data, int* size);
void BackUp(int count);
int64 ByteCount() const;
// Returns the bytes written to this stream till now.
const string& GetBytes();
// Moves bytes written to this stream to the given target.
// It is illegal to use the stream after a call to this function.
void moveBytes(string& target) {
#ifdef LANG_CXX11
target = std::move(GetBytes());
#else
target = GetBytes();
#endif
byte_count_ = 0;
}
private:
static const int kMinimumSize = 16;
string target_; // bytes are appended to this
int64 byte_count_; // number of bytes writtten till now
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream2);
};
// ===================================================================
StringOutputStream2::StringOutputStream2()
: byte_count_(0) {
}
StringOutputStream2::~StringOutputStream2() {
}
bool StringOutputStream2::Next(void** data, int* size) {
int old_size = target_.size();
// Grow the string.
if (old_size < target_.capacity()) {
// Resize the string to match its capacity, since we can get away
// without a memory allocation this way.
STLStringResizeUninitialized(&target_, target_.capacity());
} else if (byte_count_ == old_size) {
// Size has reached capacity, try to double the size.
if (old_size > std::numeric_limits<int>::max() / 2) {
// Can not double the size otherwise it is going to cause integer
// overflow in the expression below: old_size * 2 ";
GOOGLE_LOG(ERROR) << "Cannot allocate buffer larger than kint32max for "
<< "StringOutputStream2.";
return false;
}
// Double the size, also make sure that the new size is at least
// kMinimumSize.
STLStringResizeUninitialized(
&target_,
std::max(old_size * 2,
kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
}
int new_size = target_.size();
*data = mutable_string_data(&target_) + byte_count_;
*size = new_size - byte_count_;
byte_count_ = new_size;
return true;
}
void StringOutputStream2::BackUp(int count) {
GOOGLE_CHECK_GE(count, 0);
GOOGLE_CHECK_LE(count, byte_count_);
byte_count_ -= count;
}
int64 StringOutputStream2::ByteCount() const {
return byte_count_;
}
const string& StringOutputStream2::GetBytes() {
if (target_.size() != byte_count_) {
target_.resize(byte_count_);
}
return target_;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment