diff options
author | 2009-04-25 02:53:47 +0000 | |
---|---|---|
committer | 2009-04-25 02:53:47 +0000 | |
commit | d37d46dfbcedadeb439ad0367f8afcf8867dca43 (patch) | |
tree | b896df229f7c671637924c156d5a759ba50a3190 /src/google/protobuf/io | |
parent | 709ea28f3264aa5632e5577a4080671173fc6166 (diff) |
Integrate recent changes from Google-internal code tree. See CHANGES.txt
for details.
Diffstat (limited to 'src/google/protobuf/io')
-rw-r--r-- | src/google/protobuf/io/coded_stream.cc | 258 | ||||
-rw-r--r-- | src/google/protobuf/io/coded_stream.h | 179 | ||||
-rw-r--r-- | src/google/protobuf/io/coded_stream_unittest.cc | 20 | ||||
-rw-r--r-- | src/google/protobuf/io/zero_copy_stream_impl.cc | 5 |
4 files changed, 315 insertions, 147 deletions
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index a0f08571..0a00d2bb 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -71,18 +71,13 @@ CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) buffer_size_(0), total_bytes_read_(0), overflow_bytes_(0), - last_tag_(0), legitimate_message_end_(false), - aliasing_enabled_(false), - current_limit_(INT_MAX), buffer_size_after_limit_(0), - total_bytes_limit_(kDefaultTotalBytesLimit), total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), - recursion_depth_(0), recursion_limit_(kDefaultRecursionLimit) { } @@ -514,7 +509,14 @@ CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output) : output_(output), buffer_(NULL), buffer_size_(0), - total_bytes_(0) { + total_bytes_(0), + had_error_(false) { + // Eagerly Refresh() so buffer space is immediately available. + Refresh(); + // The Refresh() may have failed. If the client doesn't write any data, + // though, don't consider this an error. If the client does write data, then + // another Refresh() will be attempted and it will set the error once again. + had_error_ = false; } CodedOutputStream::~CodedOutputStream() { @@ -543,21 +545,26 @@ bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) { return true; } -bool CodedOutputStream::WriteRaw(const void* data, int size) { +void CodedOutputStream::WriteRaw(const void* data, int size) { while (buffer_size_ < size) { memcpy(buffer_, data, buffer_size_); size -= buffer_size_; data = reinterpret_cast<const uint8*>(data) + buffer_size_; - if (!Refresh()) return false; + if (!Refresh()) return; } memcpy(buffer_, data, size); Advance(size); - return true; +} + +uint8* CodedOutputStream::WriteRawToArray( + const void* data, int size, uint8* target) { + memcpy(target, data, size); + return target + size; } -bool CodedOutputStream::WriteLittleEndian32(uint32 value) { +void CodedOutputStream::WriteLittleEndian32(uint32 value) { uint8 bytes[sizeof(value)]; bool use_fast = buffer_size_ >= sizeof(value); @@ -570,13 +577,21 @@ bool CodedOutputStream::WriteLittleEndian32(uint32 value) { if (use_fast) { Advance(sizeof(value)); - return true; } else { - return WriteRaw(bytes, sizeof(value)); + WriteRaw(bytes, sizeof(value)); } } -bool CodedOutputStream::WriteLittleEndian64(uint64 value) { +uint8* CodedOutputStream::WriteLittleEndian32ToArray( + uint32 value, uint8* target) { + target[0] = static_cast<uint8>(value ); + target[1] = static_cast<uint8>(value >> 8); + target[2] = static_cast<uint8>(value >> 16); + target[3] = static_cast<uint8>(value >> 24); + return target + sizeof(value); +} + +void CodedOutputStream::WriteLittleEndian64(uint64 value) { uint8 bytes[sizeof(value)]; uint32 part0 = static_cast<uint32>(value); @@ -596,46 +611,66 @@ bool CodedOutputStream::WriteLittleEndian64(uint64 value) { if (use_fast) { Advance(sizeof(value)); - return true; } else { - return WriteRaw(bytes, sizeof(value)); + WriteRaw(bytes, sizeof(value)); } } -bool CodedOutputStream::WriteVarint32Fallback(uint32 value) { - if (buffer_size_ >= kMaxVarint32Bytes) { - // Fast path: We have enough bytes left in the buffer to guarantee that - // this write won't cross the end, so we can skip the checks. - uint8* target = buffer_; +uint8* CodedOutputStream::WriteLittleEndian64ToArray( + uint64 value, uint8* target) { + uint32 part0 = static_cast<uint32>(value); + uint32 part1 = static_cast<uint32>(value >> 32); + + target[0] = static_cast<uint8>(part0 ); + target[1] = static_cast<uint8>(part0 >> 8); + target[2] = static_cast<uint8>(part0 >> 16); + target[3] = static_cast<uint8>(part0 >> 24); + target[4] = static_cast<uint8>(part1 ); + target[5] = static_cast<uint8>(part1 >> 8); + target[6] = static_cast<uint8>(part1 >> 16); + target[7] = static_cast<uint8>(part1 >> 24); + + return target + sizeof(value); +} - target[0] = static_cast<uint8>(value | 0x80); - if (value >= (1 << 7)) { - target[1] = static_cast<uint8>((value >> 7) | 0x80); - if (value >= (1 << 14)) { - target[2] = static_cast<uint8>((value >> 14) | 0x80); - if (value >= (1 << 21)) { - target[3] = static_cast<uint8>((value >> 21) | 0x80); - if (value >= (1 << 28)) { - target[4] = static_cast<uint8>(value >> 28); - Advance(5); - } else { - target[3] &= 0x7F; - Advance(4); - } +inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline( + uint32 value, uint8* target) { + target[0] = static_cast<uint8>(value | 0x80); + if (value >= (1 << 7)) { + target[1] = static_cast<uint8>((value >> 7) | 0x80); + if (value >= (1 << 14)) { + target[2] = static_cast<uint8>((value >> 14) | 0x80); + if (value >= (1 << 21)) { + target[3] = static_cast<uint8>((value >> 21) | 0x80); + if (value >= (1 << 28)) { + target[4] = static_cast<uint8>(value >> 28); + return target + 5; } else { - target[2] &= 0x7F; - Advance(3); + target[3] &= 0x7F; + return target + 4; } } else { - target[1] &= 0x7F; - Advance(2); + target[2] &= 0x7F; + return target + 3; } } else { - target[0] &= 0x7F; - Advance(1); + target[1] &= 0x7F; + return target + 2; } + } else { + target[0] &= 0x7F; + return target + 1; + } +} - return true; +void CodedOutputStream::WriteVarint32(uint32 value) { + if (buffer_size_ >= kMaxVarint32Bytes) { + // Fast path: We have enough bytes left in the buffer to guarantee that + // this write won't cross the end, so we can skip the checks. + uint8* target = buffer_; + uint8* end = WriteVarint32FallbackToArrayInline(value, target); + int size = end - target; + Advance(size); } else { // Slow path: This write might cross the end of the buffer, so we // compose the bytes first then use WriteRaw(). @@ -646,85 +681,96 @@ bool CodedOutputStream::WriteVarint32Fallback(uint32 value) { value >>= 7; } bytes[size++] = static_cast<uint8>(value) & 0x7F; - return WriteRaw(bytes, size); + WriteRaw(bytes, size); } } -bool CodedOutputStream::WriteVarint64(uint64 value) { - if (buffer_size_ >= kMaxVarintBytes) { - // Fast path: We have enough bytes left in the buffer to guarantee that - // this write won't cross the end, so we can skip the checks. - uint8* target = buffer_; +uint8* CodedOutputStream::WriteVarint32FallbackToArray( + uint32 value, uint8* target) { + return WriteVarint32FallbackToArrayInline(value, target); +} - // Splitting into 32-bit pieces gives better performance on 32-bit - // processors. - uint32 part0 = static_cast<uint32>(value ); - uint32 part1 = static_cast<uint32>(value >> 28); - uint32 part2 = static_cast<uint32>(value >> 56); - - int size; - - // Here we can't really optimize for small numbers, since the value is - // split into three parts. Cheking for numbers < 128, for instance, - // would require three comparisons, since you'd have to make sure part1 - // and part2 are zero. However, if the caller is using 64-bit integers, - // it is likely that they expect the numbers to often be very large, so - // we probably don't want to optimize for small numbers anyway. Thus, - // we end up with a hardcoded binary search tree... - if (part2 == 0) { - if (part1 == 0) { - if (part0 < (1 << 14)) { - if (part0 < (1 << 7)) { - size = 1; goto size1; - } else { - size = 2; goto size2; - } +inline uint8* CodedOutputStream::WriteVarint64ToArrayInline( + uint64 value, uint8* target) { + // Splitting into 32-bit pieces gives better performance on 32-bit + // processors. + uint32 part0 = static_cast<uint32>(value ); + uint32 part1 = static_cast<uint32>(value >> 28); + uint32 part2 = static_cast<uint32>(value >> 56); + + int size; + + // Here we can't really optimize for small numbers, since the value is + // split into three parts. Cheking for numbers < 128, for instance, + // would require three comparisons, since you'd have to make sure part1 + // and part2 are zero. However, if the caller is using 64-bit integers, + // it is likely that they expect the numbers to often be very large, so + // we probably don't want to optimize for small numbers anyway. Thus, + // we end up with a hardcoded binary search tree... + if (part2 == 0) { + if (part1 == 0) { + if (part0 < (1 << 14)) { + if (part0 < (1 << 7)) { + size = 1; goto size1; } else { - if (part0 < (1 << 21)) { - size = 3; goto size3; - } else { - size = 4; goto size4; - } + size = 2; goto size2; } } else { - if (part1 < (1 << 14)) { - if (part1 < (1 << 7)) { - size = 5; goto size5; - } else { - size = 6; goto size6; - } + if (part0 < (1 << 21)) { + size = 3; goto size3; } else { - if (part1 < (1 << 21)) { - size = 7; goto size7; - } else { - size = 8; goto size8; - } + size = 4; goto size4; } } } else { - if (part2 < (1 << 7)) { - size = 9; goto size9; + if (part1 < (1 << 14)) { + if (part1 < (1 << 7)) { + size = 5; goto size5; + } else { + size = 6; goto size6; + } } else { - size = 10; goto size10; + if (part1 < (1 << 21)) { + size = 7; goto size7; + } else { + size = 8; goto size8; + } } } + } else { + if (part2 < (1 << 7)) { + size = 9; goto size9; + } else { + size = 10; goto size10; + } + } - GOOGLE_LOG(FATAL) << "Can't get here."; + GOOGLE_LOG(FATAL) << "Can't get here."; + + size10: target[9] = static_cast<uint8>((part2 >> 7) | 0x80); + size9 : target[8] = static_cast<uint8>((part2 ) | 0x80); + size8 : target[7] = static_cast<uint8>((part1 >> 21) | 0x80); + size7 : target[6] = static_cast<uint8>((part1 >> 14) | 0x80); + size6 : target[5] = static_cast<uint8>((part1 >> 7) | 0x80); + size5 : target[4] = static_cast<uint8>((part1 ) | 0x80); + size4 : target[3] = static_cast<uint8>((part0 >> 21) | 0x80); + size3 : target[2] = static_cast<uint8>((part0 >> 14) | 0x80); + size2 : target[1] = static_cast<uint8>((part0 >> 7) | 0x80); + size1 : target[0] = static_cast<uint8>((part0 ) | 0x80); + + target[size-1] &= 0x7F; + return target + size; +} - size10: target[9] = static_cast<uint8>((part2 >> 7) | 0x80); - size9 : target[8] = static_cast<uint8>((part2 ) | 0x80); - size8 : target[7] = static_cast<uint8>((part1 >> 21) | 0x80); - size7 : target[6] = static_cast<uint8>((part1 >> 14) | 0x80); - size6 : target[5] = static_cast<uint8>((part1 >> 7) | 0x80); - size5 : target[4] = static_cast<uint8>((part1 ) | 0x80); - size4 : target[3] = static_cast<uint8>((part0 >> 21) | 0x80); - size3 : target[2] = static_cast<uint8>((part0 >> 14) | 0x80); - size2 : target[1] = static_cast<uint8>((part0 >> 7) | 0x80); - size1 : target[0] = static_cast<uint8>((part0 ) | 0x80); +void CodedOutputStream::WriteVarint64(uint64 value) { + if (buffer_size_ >= kMaxVarintBytes) { + // Fast path: We have enough bytes left in the buffer to guarantee that + // this write won't cross the end, so we can skip the checks. + uint8* target = buffer_; - target[size-1] &= 0x7F; + uint8* end = WriteVarint64ToArrayInline(value, target); + int size = end - target; Advance(size); - return true; } else { // Slow path: This write might cross the end of the buffer, so we // compose the bytes first then use WriteRaw(). @@ -735,10 +781,15 @@ bool CodedOutputStream::WriteVarint64(uint64 value) { value >>= 7; } bytes[size++] = static_cast<uint8>(value) & 0x7F; - return WriteRaw(bytes, size); + WriteRaw(bytes, size); } } +uint8* CodedOutputStream::WriteVarint64ToArray( + uint64 value, uint8* target) { + return WriteVarint64ToArrayInline(value, target); +} + bool CodedOutputStream::Refresh() { void* void_buffer; if (output_->Next(&void_buffer, &buffer_size_)) { @@ -748,6 +799,7 @@ bool CodedOutputStream::Refresh() { } else { buffer_ = NULL; buffer_size_ = 0; + had_error_ = true; return false; } } diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index 8ebe4b35..9e450216 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -380,7 +380,46 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // // Most methods of CodedOutputStream which return a bool return false if an // underlying I/O error occurs. Once such a failure occurs, the -// CodedOutputStream is broken and is no longer useful. +// CodedOutputStream is broken and is no longer useful. The Write* methods do +// not return the stream status, but will invalidate the stream if an error +// occurs. The client can probe HadError() to determine the status. +// +// Note that every method of CodedOutputStream which writes some data has +// a corresponding static "ToArray" version. These versions write directly +// to the provided buffer, returning a pointer past the last written byte. +// They require that the buffer has sufficient capacity for the encoded data. +// This allows an optimization where we check if an output stream has enough +// space for an entire message before we start writing and, if there is, we +// call only the ToArray methods to avoid doing bound checks for each +// individual value. +// i.e., in the example above: +// +// CodedOutputStream coded_output = new CodedOutputStream(raw_output); +// int magic_number = 1234; +// char text[] = "Hello world!"; +// +// int coded_size = sizeof(magic_number) + +// CodedOutputStream::Varint32Size(strlen(text)) + +// strlen(text); +// +// uint8* buffer = +// coded_output->GetDirectBufferForNBytesAndAdvance(coded_size); +// if (buffer != NULL) { +// // The output stream has enough space in the buffer: write directly to +// // the array. +// buffer = CodedOutputStream::WriteLittleEndian32ToArray(magic_number, +// buffer); +// buffer = CodedOutputStream::WriteVarint32ToArray(strlen(text), buffer); +// buffer = CodedOutputStream::WriteRawToArray(text, strlen(text), buffer); +// } else { +// // Make bound-checked writes, which will ask the underlying stream for +// // more space as needed. +// coded_output->WriteLittleEndian32(magic_number); +// coded_output->WriteVarint32(strlen(text)); +// coded_output->WriteRaw(text, strlen(text)); +// } +// +// delete coded_output; class LIBPROTOBUF_EXPORT CodedOutputStream { public: // Create an CodedOutputStream that writes to the given ZeroCopyOutputStream. @@ -405,35 +444,65 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // CodedOutputStream interface. bool GetDirectBufferPointer(void** data, int* size); + // If there are at least "size" bytes available in the current buffer, + // returns a pointer directly into the buffer and advances over these bytes. + // The caller may then write directly into this buffer (e.g. using the + // *ToArray static methods) rather than go through CodedOutputStream. If + // there are not enough bytes available, returns NULL. The return pointer is + // invalidated as soon as any other non-const method of CodedOutputStream + // is called. + inline uint8* GetDirectBufferForNBytesAndAdvance(int size); + // Write raw bytes, copying them from the given buffer. - bool WriteRaw(const void* buffer, int size); + void WriteRaw(const void* buffer, int size); + // Like WriteRaw() but writing directly to the target array. + // This is _not_ inlined, as the compiler often optimizes memcpy into inline + // copy loops. Since this gets called by every field with string or bytes + // type, inlining may lead to a significant amount of code bloat, with only a + // minor performance gain. + static uint8* WriteRawToArray(const void* buffer, int size, uint8* target); // Equivalent to WriteRaw(str.data(), str.size()). - bool WriteString(const string& str); + void WriteString(const string& str); + // Like WriteString() but writing directly to the target array. + static uint8* WriteStringToArray(const string& str, uint8* target); // Write a 32-bit little-endian integer. - bool WriteLittleEndian32(uint32 value); + void WriteLittleEndian32(uint32 value); + // Like WriteLittleEndian32() but writing directly to the target array. + static uint8* WriteLittleEndian32ToArray(uint32 value, uint8* target); // Write a 64-bit little-endian integer. - bool WriteLittleEndian64(uint64 value); + void WriteLittleEndian64(uint64 value); + // Like WriteLittleEndian64() but writing directly to the target array. + static uint8* WriteLittleEndian64ToArray(uint64 value, uint8* target); // Write an unsigned integer with Varint encoding. Writing a 32-bit value // is equivalent to casting it to uint64 and writing it as a 64-bit value, // but may be more efficient. - bool WriteVarint32(uint32 value); + void WriteVarint32(uint32 value); + // Like WriteVarint32() but writing directly to the target array. + static uint8* WriteVarint32ToArray(uint32 value, uint8* target); // Write an unsigned integer with Varint encoding. - bool WriteVarint64(uint64 value); + void WriteVarint64(uint64 value); + // Like WriteVarint64() but writing directly to the target array. + static uint8* WriteVarint64ToArray(uint64 value, uint8* target); // Equivalent to WriteVarint32() except when the value is negative, // in which case it must be sign-extended to a full 10 bytes. - bool WriteVarint32SignExtended(int32 value); + void WriteVarint32SignExtended(int32 value); + // Like WriteVarint32SignExtended() but writing directly to the target array. + static uint8* WriteVarint32SignExtendedToArray(int32 value, uint8* target); // This is identical to WriteVarint32(), but optimized for writing tags. // In particular, if the input is a compile-time constant, this method // compiles down to a couple instructions. // Always inline because otherwise the aformentioned optimization can't work, // but GCC by default doesn't want to inline this. - bool WriteTag(uint32 value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + void WriteTag(uint32 value); + // Like WriteTag() but writing directly to the target array. + static uint8* WriteTagToArray( + uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; // Returns the number of bytes needed to encode the given value as a varint. static int VarintSize32(uint32 value); @@ -446,6 +515,10 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // Returns the total number of bytes written since this object was created. inline int ByteCount() const; + // Returns true if there was an underlying I/O error since this object was + // created. + bool HadError() const { return had_error_; } + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedOutputStream); @@ -453,6 +526,7 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { uint8* buffer_; int buffer_size_; int total_bytes_; // Sum of sizes of all buffers seen so far. + bool had_error_; // Whether an error occurred during output. // Advance the buffer by a given number of bytes. void Advance(int amount); @@ -461,7 +535,20 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // Advance(buffer_size_). bool Refresh(); - bool WriteVarint32Fallback(uint32 value); + static uint8* WriteVarint32FallbackToArray(uint32 value, uint8* target); + + // Always-inlined versions of WriteVarint* functions so that code can be + // reused, while still controlling size. For instance, WriteVarint32ToArray() + // should not directly call this: since it is inlined itself, doing so + // would greatly increase the size of generated code. Instead, it should call + // WriteVarint32FallbackToArray. Meanwhile, WriteVarint32() is already + // out-of-line, so it should just invoke this directly to avoid any extra + // function call overhead. + static uint8* WriteVarint32FallbackToArrayInline( + uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + static uint8* WriteVarint64ToArrayInline( + uint64 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + static int VarintSize32Fallback(uint32 value); }; @@ -540,40 +627,59 @@ inline bool CodedInputStream::ExpectAtEnd() { } } -inline bool CodedOutputStream::WriteVarint32(uint32 value) { - if (value < 0x80 && buffer_size_ > 0) { - *buffer_ = static_cast<uint8>(value); - Advance(1); - return true; +inline uint8* CodedOutputStream::GetDirectBufferForNBytesAndAdvance(int size) { + if (buffer_size_ < size) { + return NULL; + } else { + uint8* result = buffer_; + Advance(size); + return result; + } +} + +inline uint8* CodedOutputStream::WriteVarint32ToArray(uint32 value, + uint8* target) { + if (value < 0x80) { + *target = value; + return target + 1; } else { - return WriteVarint32Fallback(value); + return WriteVarint32FallbackToArray(value, target); } } -inline bool CodedOutputStream::WriteVarint32SignExtended(int32 value) { +inline void CodedOutputStream::WriteVarint32SignExtended(int32 value) { if (value < 0) { - return WriteVarint64(static_cast<uint64>(value)); + WriteVarint64(static_cast<uint64>(value)); } else { - return WriteVarint32(static_cast<uint32>(value)); + WriteVarint32(static_cast<uint32>(value)); } } -inline bool CodedOutputStream::WriteTag(uint32 value) { +inline uint8* CodedOutputStream::WriteVarint32SignExtendedToArray( + int32 value, uint8* target) { + if (value < 0) { + return WriteVarint64ToArray(static_cast<uint64>(value), target); + } else { + return WriteVarint32ToArray(static_cast<uint32>(value), target); + } +} + +inline void CodedOutputStream::WriteTag(uint32 value) { + WriteVarint32(value); +} + +inline uint8* CodedOutputStream::WriteTagToArray( + uint32 value, uint8* target) { if (value < (1 << 7)) { - if (buffer_size_ != 0) { - buffer_[0] = static_cast<uint8>(value); - Advance(1); - return true; - } + target[0] = value; + return target + 1; } else if (value < (1 << 14)) { - if (buffer_size_ >= 2) { - buffer_[0] = static_cast<uint8>(value | 0x80); - buffer_[1] = static_cast<uint8>(value >> 7); - Advance(2); - return true; - } + target[0] = static_cast<uint8>(value | 0x80); + target[1] = static_cast<uint8>(value >> 7); + return target + 2; + } else { + return WriteVarint32FallbackToArray(value, target); } - return WriteVarint32Fallback(value); } inline int CodedOutputStream::VarintSize32(uint32 value) { @@ -592,8 +698,13 @@ inline int CodedOutputStream::VarintSize32SignExtended(int32 value) { } } -inline bool CodedOutputStream::WriteString(const string& str) { - return WriteRaw(str.data(), str.size()); +inline void CodedOutputStream::WriteString(const string& str) { + WriteRaw(str.data(), str.size()); +} + +inline uint8* CodedOutputStream::WriteStringToArray( + const string& str, uint8* target) { + return WriteRawToArray(str.data(), str.size(), target); } inline int CodedOutputStream::ByteCount() const { diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index 6a6eafe9..e165fb93 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -268,8 +268,8 @@ TEST_2D(CodedStreamTest, WriteVarint32, kVarintCases, kBlockSizes) { { CodedOutputStream coded_output(&output); - EXPECT_TRUE(coded_output.WriteVarint32( - static_cast<uint32>(kVarintCases_case.value))); + coded_output.WriteVarint32(static_cast<uint32>(kVarintCases_case.value)); + EXPECT_FALSE(coded_output.HadError()); EXPECT_EQ(kVarintCases_case.size, coded_output.ByteCount()); } @@ -285,7 +285,8 @@ TEST_2D(CodedStreamTest, WriteVarint64, kVarintCases, kBlockSizes) { { CodedOutputStream coded_output(&output); - EXPECT_TRUE(coded_output.WriteVarint64(kVarintCases_case.value)); + coded_output.WriteVarint64(kVarintCases_case.value); + EXPECT_FALSE(coded_output.HadError()); EXPECT_EQ(kVarintCases_case.size, coded_output.ByteCount()); } @@ -310,8 +311,8 @@ TEST_2D(CodedStreamTest, WriteVarint32SignExtended, { CodedOutputStream coded_output(&output); - EXPECT_TRUE(coded_output.WriteVarint32SignExtended( - kSignExtendedVarintCases_case)); + coded_output.WriteVarint32SignExtended(kSignExtendedVarintCases_case); + EXPECT_FALSE(coded_output.HadError()); if (kSignExtendedVarintCases_case < 0) { EXPECT_EQ(10, coded_output.ByteCount()); @@ -502,7 +503,8 @@ TEST_2D(CodedStreamTest, WriteLittleEndian32, kFixed32Cases, kBlockSizes) { { CodedOutputStream coded_output(&output); - EXPECT_TRUE(coded_output.WriteLittleEndian32(kFixed32Cases_case.value)); + coded_output.WriteLittleEndian32(kFixed32Cases_case.value); + EXPECT_FALSE(coded_output.HadError()); EXPECT_EQ(sizeof(uint32), coded_output.ByteCount()); } @@ -517,7 +519,8 @@ TEST_2D(CodedStreamTest, WriteLittleEndian64, kFixed64Cases, kBlockSizes) { { CodedOutputStream coded_output(&output); - EXPECT_TRUE(coded_output.WriteLittleEndian64(kFixed64Cases_case.value)); + coded_output.WriteLittleEndian64(kFixed64Cases_case.value); + EXPECT_FALSE(coded_output.HadError()); EXPECT_EQ(sizeof(uint64), coded_output.ByteCount()); } @@ -552,7 +555,8 @@ TEST_1D(CodedStreamTest, WriteRaw, kBlockSizes) { { CodedOutputStream coded_output(&output); - EXPECT_TRUE(coded_output.WriteRaw(kRawBytes, sizeof(kRawBytes))); + coded_output.WriteRaw(kRawBytes, sizeof(kRawBytes)); + EXPECT_FALSE(coded_output.HadError()); EXPECT_EQ(sizeof(kRawBytes), coded_output.ByteCount()); } diff --git a/src/google/protobuf/io/zero_copy_stream_impl.cc b/src/google/protobuf/io/zero_copy_stream_impl.cc index 730bd2f7..0b4516ef 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl.cc @@ -185,11 +185,12 @@ bool StringOutputStream::Next(void** data, int* size) { if (old_size < target_->capacity()) { // Resize the string to match its capacity, since we can get away // without a memory allocation this way. - target_->resize(target_->capacity()); + STLStringResizeUninitialized(target_, target_->capacity()); } else { // Size has reached capacity, so double the size. Also make sure // that the new size is at least kMinimumSize. - target_->resize( + STLStringResizeUninitialized( + target_, max(old_size * 2, kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness. } |