Done. But it occurs to me that this isn't all that much nicer a solution
than just calling getSerializedSize() in writeTo(CodedOutputStream
output), except that it only happens for messages with packed fields,
rather than all messages. Should this compute only the serialized size
of the packed field, so that it doesn't needlessly compute the size of
all the unpacked fields? Or does this not really matter? I think all of
the wrappers now call getSerializedSize() thanks to r240 (I was tearing
my hair out trying to figure out why I could not get a new test which
just did
ByteArrayOutputStream output = new ByteArrayOutputStream();
message.writeTo(output);
would not fail from the open source code, but would if I added the same
test to our internal version, until I finally looked at the source).
Anyway point being that in most cases getSerializedSize() will have
already been called anyway so maybe it doesn't matter too much if we
compute the size of the entire message rather than just the packed
fields.

On 2009/11/25 03:42:18, kenton wrote:
> On Tue, Nov 24, 2009 at 7:40 PM, Kenton Varda
<mailto:ken...@google.com> wrote:

> > I guess it's technically the case that a packed field always has
non-zero
> > size, but maybe we should initialize the cached sizes to -1 anyway
to make
> > it more clear when they haven't been initialized?


> That was a confusing sentence.  Change "when they haven't been
initialized"
> to "when getSerializedSize() hasn't been called".


> >
> > On Tue, Nov 24, 2009 at 7:04 PM, <mailto:jas...@google.com> wrote:
> >
> >> Reviewers: kenton,
> >>
> >> Description:
> >> Fix Issue 136: the memoized serialized size for packed fields may
not
> >> be properly set. writeTo() may be invoked without a call to
> >> getSerializedSize(), so the generated serialization methods would
> >> write a length of 0 for non-empty packed fields. Since the object
> >> is immutable, we know that the memoized size is 0 or set to the
> >> correct size. In the generated code, check to see if the memoized
> >> size is 0, and if so, call getSerializedSize() before actually
> >> emitting the field.
> >>
> >> Tested: new unittest case in WireFormatTest.java now passes
> >>
> >>
> >>
> >> Please review this at http://codereview.appspot.com/157169
> >>
> >> Affected files:
> >>  M     java/src/test/java/com/google/protobuf/WireFormatTest.java
> >>  M     src/google/protobuf/compiler/java/java_primitive_field.cc
> >>
> >>
> >> Index: java/src/test/java/com/google/protobuf/WireFormatTest.java
> >> ===================================================================
> >> --- java/src/test/java/com/google/protobuf/WireFormatTest.java
(revision
> >> 246)
> >> +++ java/src/test/java/com/google/protobuf/WireFormatTest.java
(working
> >> copy)
> >> @@ -102,6 +102,28 @@
> >>     assertEquals(rawBytes, rawBytes2);
> >>   }
> >>
> >> +  public void testSerializationPackedWithoutGetSerializedSize()
> >> +      throws Exception {
> >> +    // Write directly to an OutputStream, without invoking
> >> getSerializedSize()
> >> +    // This used to be a bug where the size of a packed field was
> >> incorrect,
> >> +    // since getSerializedSize() was never invoked.
> >> +    TestPackedTypes message = TestUtil.getPackedSet();
> >> +
> >> +    // Directly construct a CodedOutputStream around the actual
> >> OutputStream,
> >> +    // because writeTo() now invokes getSerializedSize();
> >> +    ByteArrayOutputStream outputStream = new
ByteArrayOutputStream();
> >> +    CodedOutputStream codedOutput =
> >> CodedOutputStream.newInstance(outputStream);
> >> +
> >> +    message.writeTo(codedOutput);
> >> +
> >> +    codedOutput.flush();
> >> +
> >> +    TestPackedTypes message2 = TestPackedTypes.parseFrom(
> >> +        outputStream.toByteArray());
> >> +
> >> +    TestUtil.assertPackedFieldsSet(message2);
> >> +  }
> >> +
> >>   public void testSerializeExtensionsLite() throws Exception {
> >>     // TestAllTypes and TestAllExtensions should have compatible
wire
> >> formats,
> >>     // so if we serialize a TestAllExtensions then parse it as
> >> TestAllTypes
> >> Index: src/google/protobuf/compiler/java/java_primitive_field.cc
> >> ===================================================================
> >> --- src/google/protobuf/compiler/java/java_primitive_field.cc
(revision
> >> 246)
> >> +++ src/google/protobuf/compiler/java/java_primitive_field.cc
(working
> >> copy)
> >> @@ -384,8 +384,17 @@
> >>  void RepeatedPrimitiveFieldGenerator::
> >>  GenerateSerializationCode(io::Printer* printer) const {
> >>   if (descriptor_->options().packed()) {
> >> +    // writeTo() may be called without getSerializedSize() ever
having
> >> been
> >> +    // called, so we may need to compute the length of the packed
data.
> >> Since
> >> +    // the object is immutable, we know that the memoized size is
either
> >> set to
> >> +    // 0 (via object initialization) or else it has the correct
size from
> >> a
> >> +    // previous getSerializedSize() call. If the field is not
empty and
> >> the size
> >> +    // has not yet been computed, just call getSerializedSize()
> >>     printer->Print(variables_,
> >>       "if (get$capitalized_name$List().size() > 0) {\n"
> >> +      "  if ($name$MemoizedSerializedSize == 0) {\n"
> >> +      "    getSerializedSize();\n"
> >> +      "  }\n"
> >>       "  output.writeRawVarint32($tag$);\n"
> >>       "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
> >>       "}\n"
> >>
> >>
> >>
> >




http://codereview.appspot.com/157169

--

You received this message because you are subscribed to the Google Groups 
"Protocol Buffers" group.
To post to this group, send email to proto...@googlegroups.com.
To unsubscribe from this group, send email to 
protobuf+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/protobuf?hl=en.


Reply via email to