aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/io
diff options
context:
space:
mode:
authorGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-04-25 02:53:47 +0000
committerGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-04-25 02:53:47 +0000
commitd37d46dfbcedadeb439ad0367f8afcf8867dca43 (patch)
treeb896df229f7c671637924c156d5a759ba50a3190 /src/google/protobuf/io
parent709ea28f3264aa5632e5577a4080671173fc6166 (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.cc258
-rw-r--r--src/google/protobuf/io/coded_stream.h179
-rw-r--r--src/google/protobuf/io/coded_stream_unittest.cc20
-rw-r--r--src/google/protobuf/io/zero_copy_stream_impl.cc5
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.
}