Skip to content

Commit 28f62eb

Browse files
Fix IDLObjectSequence#calculateSizeBytes for variable-size elements (#103)
1 parent f7513d7 commit 28f62eb

3 files changed

Lines changed: 117 additions & 4 deletions

File tree

src/main/java/us/ihmc/fastddsjava/cdr/idl/IDLObjectSequence.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,25 @@ public int elementSizeBytes(int currentAlignment, int i)
231231
return elements[i].calculateSizeBytes(currentAlignment);
232232
}
233233

234+
/**
235+
* Object elements already include their own alignment padding in {@link #elementSizeBytes(int, int)},
236+
* so the base {@link IDLSequence#calculateSizeBytes(int)} loop must not add a second alignment pass.
237+
*/
238+
@Override
239+
public int calculateSizeBytes(int currentAlignment)
240+
{
241+
int initialAlignment = currentAlignment;
242+
243+
currentAlignment += 4 + CDRBuffer.alignment(currentAlignment, 4); // Length header
244+
245+
for (int i = 0; i < size(); i++)
246+
{
247+
currentAlignment += elementSizeBytes(currentAlignment, i);
248+
}
249+
250+
return currentAlignment - initialAlignment;
251+
}
252+
234253
@Override
235254
public void readElement(CDRBuffer buffer)
236255
{

src/main/java/us/ihmc/jros2/ROS2Publisher.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,11 @@ private void writeAndPublish(T message, boolean recordStatistics)
205205
{
206206
writeBuffer.rewind();
207207

208-
// For fixed-size messages the payload length is stable after construction preallocation.
209-
payloadSizeBytes = CDRBuffer.PAYLOAD_HEADER.length + message.calculateSizeBytes(0);
210-
if (payloadSizeBytes > writeBuffer.getBufferUnsafe().capacity())
208+
// Presize from calculateSizeBytes; actual payload length is the buffer position after serialize.
209+
int estimatedSizeBytes = CDRBuffer.PAYLOAD_HEADER.length + message.calculateSizeBytes(0);
210+
if (estimatedSizeBytes > writeBuffer.getBufferUnsafe().capacity())
211211
{
212-
writeBuffer.ensureRemainingCapacity(payloadSizeBytes);
212+
writeBuffer.ensureRemainingCapacity(estimatedSizeBytes);
213213
}
214214

215215
writeBuffer.writePayloadHeader();
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package us.ihmc.fastddsjava.cdr.idl;
2+
3+
import org.junit.jupiter.api.Test;
4+
import us.ihmc.fastddsjava.cdr.CDRBuffer;
5+
import us.ihmc.fastddsjava.cdr.CDRSerializable;
6+
7+
import static org.junit.jupiter.api.Assertions.assertEquals;
8+
9+
/**
10+
* Checks {@link IDLObjectSequence#calculateSizeBytes(int)} against serialize() for variable-size elements.
11+
*/
12+
public class IDLObjectSequenceVariableSizeElementTest
13+
{
14+
/** Element with a string field so encoded size is not a fixed CDR alignment boundary. */
15+
static class VariableSizeMsg implements CDRSerializable
16+
{
17+
private int id;
18+
private final StringBuilder name = new StringBuilder();
19+
20+
@Override
21+
public int calculateSizeBytes(int currentAlignment)
22+
{
23+
int initialAlignment = currentAlignment;
24+
currentAlignment += 4 + CDRBuffer.alignment(currentAlignment, 4); // id
25+
currentAlignment += 4 + CDRBuffer.alignment(currentAlignment, 4) + name.length() + 1; // name
26+
return currentAlignment - initialAlignment;
27+
}
28+
29+
@Override
30+
public void serialize(CDRBuffer buffer)
31+
{
32+
buffer.writeInt(id);
33+
buffer.writeString(name);
34+
}
35+
36+
@Override
37+
public void deserialize(CDRBuffer buffer)
38+
{
39+
id = buffer.readInt();
40+
buffer.readString(name);
41+
}
42+
}
43+
44+
@Test
45+
public void testCalculateSizeBytesMatchesActualSerializedSize()
46+
{
47+
IDLObjectSequence<VariableSizeMsg> sequence = new IDLObjectSequence<>(VariableSizeMsg.class);
48+
49+
VariableSizeMsg first = sequence.add();
50+
first.id = 1;
51+
first.name.append("pelvis"); // 6 chars -> element size is not a power of two
52+
53+
VariableSizeMsg second = sequence.add();
54+
second.id = 2;
55+
second.name.append("thigh"); // 5 chars
56+
57+
int calculatedSizeBytes = sequence.calculateSizeBytes(0);
58+
59+
CDRBuffer buffer = new CDRBuffer();
60+
buffer.ensureRemainingCapacity(CDRBuffer.PAYLOAD_HEADER.length + calculatedSizeBytes);
61+
buffer.writePayloadHeader();
62+
sequence.serialize(buffer);
63+
64+
int actualSizeBytes = buffer.getBufferUnsafe().position() - CDRBuffer.PAYLOAD_HEADER.length;
65+
66+
assertEquals(actualSizeBytes, calculatedSizeBytes, "calculateSizeBytes must match serialize byte count");
67+
}
68+
69+
@Test
70+
public void testDeserializeRoundTrip()
71+
{
72+
IDLObjectSequence<VariableSizeMsg> sequence = new IDLObjectSequence<>(VariableSizeMsg.class);
73+
sequence.add().id = 42;
74+
sequence.get(0).name.append("longer_frame_name_example");
75+
sequence.add().id = 7;
76+
sequence.get(1).name.append("x");
77+
78+
CDRBuffer buffer = new CDRBuffer();
79+
buffer.ensureRemainingCapacity(CDRBuffer.PAYLOAD_HEADER.length + sequence.calculateSizeBytes(0));
80+
buffer.writePayloadHeader();
81+
sequence.serialize(buffer);
82+
buffer.rewind();
83+
buffer.readPayloadHeader();
84+
85+
IDLObjectSequence<VariableSizeMsg> deserialized = new IDLObjectSequence<>(VariableSizeMsg.class);
86+
deserialized.deserialize(buffer);
87+
88+
assertEquals(2, deserialized.size());
89+
assertEquals(42, deserialized.get(0).id);
90+
assertEquals("longer_frame_name_example", deserialized.get(0).name.toString());
91+
assertEquals(7, deserialized.get(1).id);
92+
assertEquals("x", deserialized.get(1).name.toString());
93+
}
94+
}

0 commit comments

Comments
 (0)