Skip to content

Commit e7fa47c

Browse files
authored
Merge pull request #568 from ZachBray/feature/csharp/uint32-group-size-support
[C#] support for `uint32` representation of group size
2 parents 337ef8b + 59c7357 commit e7fa47c

File tree

4 files changed

+150
-2
lines changed

4 files changed

+150
-2
lines changed

sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,24 @@ private void generateGroupClassHeader(
181181
dimensionsClassName,
182182
parentMessageClassName));
183183

184+
final Token numInGroupToken = tokens.get(index + 3);
185+
final boolean isIntCastSafe = isRepresentableByInt32(numInGroupToken.encoding());
186+
187+
if (!isIntCastSafe)
188+
{
189+
throw new IllegalArgumentException(String.format(
190+
"%s.numInGroup - cannot be represented safely by an int. Please constrain the maxValue.",
191+
groupName));
192+
}
193+
184194
sb.append(String.format("\n" +
185195
indent + INDENT + "public void WrapForDecode(%s parentMessage, DirectBuffer buffer, int actingVersion)\n" +
186196
indent + INDENT + "{\n" +
187197
indent + INDENT + INDENT + "_parentMessage = parentMessage;\n" +
188198
indent + INDENT + INDENT + "_buffer = buffer;\n" +
189199
indent + INDENT + INDENT + "_dimensions.Wrap(buffer, parentMessage.Limit, actingVersion);\n" +
190200
indent + INDENT + INDENT + "_blockLength = _dimensions.BlockLength;\n" +
191-
indent + INDENT + INDENT + "_count = _dimensions.NumInGroup;\n" +
201+
indent + INDENT + INDENT + "_count = (int) _dimensions.NumInGroup;\n" + // cast safety checked above
192202
indent + INDENT + INDENT + "_actingVersion = actingVersion;\n" +
193203
indent + INDENT + INDENT + "_index = -1;\n" +
194204
indent + INDENT + INDENT + "_parentMessage.Limit = parentMessage.Limit + SbeHeaderSize;\n" +
@@ -197,7 +207,6 @@ private void generateGroupClassHeader(
197207

198208
final int blockLength = tokens.get(index).encodedLength();
199209
final String typeForBlockLength = cSharpTypeName(tokens.get(index + 2).encoding().primitiveType());
200-
final Token numInGroupToken = tokens.get(index + 3);
201210
final String typeForNumInGroup = cSharpTypeName(numInGroupToken.encoding().primitiveType());
202211

203212
sb.append(String.format("\n" +
@@ -233,6 +242,11 @@ private void generateGroupClassHeader(
233242
blockLength,
234243
dimensionHeaderLength));
235244

245+
generateGroupEnumerator(sb, groupName, indent);
246+
}
247+
248+
private void generateGroupEnumerator(final StringBuilder sb, final String groupName, final String indent)
249+
{
236250
sb.append(
237251
indent + INDENT + "public int ActingBlockLength { get { return _blockLength; } }\n\n" +
238252
indent + INDENT + "public int Count { get { return _count; } }\n\n" +
@@ -262,6 +276,13 @@ private void generateGroupClassHeader(
262276
indent + INDENT + "}\n");
263277
}
264278

279+
private boolean isRepresentableByInt32(final Encoding encoding)
280+
{
281+
// These min and max values are the same in .NET
282+
return encoding.applicableMinValue().longValue() >= Integer.MIN_VALUE &&
283+
encoding.applicableMaxValue().longValue() <= Integer.MAX_VALUE;
284+
}
285+
265286
private CharSequence generateGroupProperty(final String groupName, final Token token, final String indent)
266287
{
267288
final StringBuilder sb = new StringBuilder();
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package uk.co.real_logic.sbe.generation.csharp;
2+
3+
import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse;
4+
5+
import org.agrona.generation.StringWriterOutputManager;
6+
import org.junit.Test;
7+
8+
import uk.co.real_logic.sbe.TestUtil;
9+
import uk.co.real_logic.sbe.ir.Ir;
10+
import uk.co.real_logic.sbe.xml.IrGenerator;
11+
import uk.co.real_logic.sbe.xml.MessageSchema;
12+
import uk.co.real_logic.sbe.xml.ParserOptions;
13+
14+
public class Issue567GroupSizeTest
15+
{
16+
@Test(expected = IllegalArgumentException.class)
17+
public void shouldThrowWhenUsingATypeThatIsNotConstrainedToFitInAnIntAsTheGroupSize() throws Exception
18+
{
19+
// Arrange
20+
final ParserOptions options = ParserOptions.builder().stopOnError(true).build();
21+
final MessageSchema schema = parse(TestUtil.getLocalResource("issue567-invalid.xml"), options);
22+
final IrGenerator irg = new IrGenerator();
23+
final Ir ir = irg.generate(schema);
24+
25+
final StringWriterOutputManager outputManager = new StringWriterOutputManager();
26+
outputManager.setPackageName(ir.applicableNamespace());
27+
final CSharpGenerator generator = new CSharpGenerator(ir, outputManager);
28+
29+
// Act + Assert (exception thrown)
30+
generator.generate();
31+
}
32+
33+
@Test
34+
public void shouldGenerateWhenUsingATypeThatIsConstrainedToFitInAnIntAsTheGroupSize() throws Exception
35+
{
36+
// Arrange
37+
final ParserOptions options = ParserOptions.builder().stopOnError(true).build();
38+
final MessageSchema schema = parse(TestUtil.getLocalResource("issue567-valid.xml"), options);
39+
final IrGenerator irg = new IrGenerator();
40+
final Ir ir = irg.generate(schema);
41+
42+
final StringWriterOutputManager outputManager = new StringWriterOutputManager();
43+
outputManager.setPackageName(ir.applicableNamespace());
44+
final CSharpGenerator generator = new CSharpGenerator(ir, outputManager);
45+
46+
// Act + Assert (no exception)
47+
generator.generate();
48+
}
49+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<sbe:messageSchema xmlns:sbe="http://fixprotocol.io/2016/sbe"
3+
package="issue567Invalid"
4+
id="567"
5+
version="0"
6+
semanticVersion="5.2"
7+
description="issue 567 example where group size doesn't fit in an int32"
8+
byteOrder="littleEndian">
9+
<types>
10+
<composite name="messageHeader" description="Message identifiers and length of message root">
11+
<type name="blockLength" primitiveType="uint16"/>
12+
<type name="templateId" primitiveType="uint16"/>
13+
<type name="schemaId" primitiveType="uint16"/>
14+
<type name="version" primitiveType="uint16"/>
15+
</composite>
16+
<composite name="groupSizeEncoding" description="Repeating group dimensions">
17+
<type name="blockLength" primitiveType="uint16"/>
18+
<type name="numInGroup" primitiveType="uint32"/>
19+
</composite>
20+
<composite name="varStringEncoding">
21+
<type name="length" primitiveType="uint32" maxValue="1073741824"/>
22+
<type name="varData" primitiveType="uint8" length="0" characterEncoding="UTF-8"/>
23+
</composite>
24+
<composite name="varDataEncoding">
25+
<type name="length" primitiveType="uint32" maxValue="1073741824"/>
26+
<type name="varData" primitiveType="uint8" length="0"/>
27+
</composite>
28+
</types>
29+
<types>
30+
<composite name="issue567Element" description="element for group exposing issue 567">
31+
<type name="id" primitiveType="int32" />
32+
</composite>
33+
</types>
34+
<sbe:message name="issue567" id="1" description="issue 567 test">
35+
<group name="group" id="1">
36+
<field name="groupField" id="2" type="issue567Element" />
37+
</group>
38+
</sbe:message>
39+
</sbe:messageSchema>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<sbe:messageSchema xmlns:sbe="http://fixprotocol.io/2016/sbe"
3+
package="issue567Valid"
4+
id="567"
5+
version="0"
6+
semanticVersion="5.2"
7+
description="issue 567 example where group size doesn't fit in an int32"
8+
byteOrder="littleEndian">
9+
<types>
10+
<composite name="messageHeader" description="Message identifiers and length of message root">
11+
<type name="blockLength" primitiveType="uint16"/>
12+
<type name="templateId" primitiveType="uint16"/>
13+
<type name="schemaId" primitiveType="uint16"/>
14+
<type name="version" primitiveType="uint16"/>
15+
</composite>
16+
<composite name="groupSizeEncoding" description="Repeating group dimensions">
17+
<type name="blockLength" primitiveType="uint16"/>
18+
<type name="numInGroup" primitiveType="uint32" maxValue="2147483647" />
19+
</composite>
20+
<composite name="varStringEncoding">
21+
<type name="length" primitiveType="uint32" maxValue="1073741824"/>
22+
<type name="varData" primitiveType="uint8" length="0" characterEncoding="UTF-8"/>
23+
</composite>
24+
<composite name="varDataEncoding">
25+
<type name="length" primitiveType="uint32" maxValue="1073741824"/>
26+
<type name="varData" primitiveType="uint8" length="0"/>
27+
</composite>
28+
</types>
29+
<types>
30+
<composite name="issue567Element" description="element for group exposing issue 567">
31+
<type name="id" primitiveType="int32" />
32+
</composite>
33+
</types>
34+
<sbe:message name="issue567" id="1" description="issue 567 test">
35+
<group name="group" id="1">
36+
<field name="groupField" id="2" type="issue567Element" />
37+
</group>
38+
</sbe:message>
39+
</sbe:messageSchema>

0 commit comments

Comments
 (0)